iiifiiiiiiiMm
JIM BUTTERFIELD
MACHINE LANGUAGE!
FOR THE COMMODORE 64, 128, AND
MACHINE
LANGUAGE
FOR THE
COMMODORE 64, 128,
and Other
Commodore
Computers
Jim Butterfield
A Brady Book
Published by Prentice IHall Press
New Yorl<, New York 10023
Machine Language for the Commodore 64, 128, and Other
Commodore Computers
Copyright © 1986 by Brady Communications Company, Inc.
All rights reserved
Including the right of reproduction
In whole or in part in any fonn
A Brady Book
Published by Prentice l-iall Press
A Division of Simon & Schuster, Inc.
Gulf + Western Building
One Gulf + Westem Plaza
New York, New York 10023
PRENTICE HALL PRESS is a trademark of Simon & Schuster, Inc.
Manufactured in the United States of^merica
123456789 10
Library of Congress Cataloging in Pubiication Data
Butterfield, Jim
Machine language for the Commodore 64, 128, and
other Commodore computers
Includes index.
1. Commodore 64 (Computer) — Programming. 2. Commodore
computers— Programming. 3. Programming languages
(Electronic computers) I. Title.
QA76.8.C64B88 1986 001.64'2 84-6351
ISBN D-flRBDa-bBa-fl
Contents
Note to Readers
Preface
Introduction
1 First Concepts
vii
ix
xiii
1
The Inner Workings of Microcomputers
l\^emory Elements
Microprocessor Registers
Instruction Execution
First Program Project
Monitors: What They Are
The Machine Language Monitor
MLM Commands
Changing Memory Contents
Changing Registers
Entering the Program
Things You Have Learned
Detail: Program Execution
Questions and Projects
2 Controlling Output 23
Calling Machine Language Subroutines
CHROUT— The Output Subroutine
Why Not POKE?
A Print Project
Monitor Extensions
Checking: The Disassembler
Running the Program
Linking with BASIC
Loops
Things You Have Learned
Questions and Projects
ill
3 Flags, Logic, and Input 39
Flags
A Brief Diversion: Signed Numbers
A Brief Diversion: Overflow
Flag Summary
The Status Register
Instructions: A Review
Logical Operators
Why Logical Operations?
Input: The GETIN Subroutine
STOP
Programming Project
Things You Have Learned
Questions and Projects
4 Numbers, Arithmetic, and Subroutines 57
Numbers: Signed and Unsigned
Big Numbers: Multiple Bytes
Addition
Subtraction
Comparing Numbers
Multiplication
Subroutines
The Project
Things You Have Learned
Questions and Projects
5 Address Ixodes 71
Addressing Modes
No Address: Implied Mode
No Address: Accumulator Mode
Not Quite an Address: Immediate Mode
A Single Address: Absolute Mode
Zero-Page Mode
A Range of 256 Addresses: Absolute, Indexed Mode
All of Zero Page: Zero-Page, Indexed
Branching: Relative Address Mode
iv
Data From Anywhere: Indirect, Indexed
A Rarity: Indexed, Indirect
Project: Screen Manipulation
Comment for VIC-20 and Commodore 64
Things You Have Learned
Questions and Projects
6 Linking BASIC and IVIachine Language 91
Siting the Program
BASIC Memory Layout
The Wicl<ed SOV
BASIC N^afiables
Exchanging Data: BASIC and Machine Language
Things You Have Learned
Questions and Projects
7 Staci(, USR, interrufJt, atld Wedge 111
A Brief Intermission
Temporary Storage: The Stack
Interrupts and RTI
USR: A Brother to SYS
Interrupts: NMI, IRQ, and BRK
An Interrupt Project
The lA Chips: PIA, VIA, and CIA
Infiltrating BASIC: The Wedge
Project: Adding a Command
Things You Have Learned
Questions and Projects
8 Timing, Input/Output, and Conclusion 131
Timing
Input and Output
A File Transfer Program
Review: The Instruction Set
Debugging
Symbolic Assemblers
What You Have Learned
Questions and Projects
V
Appendix A
The 6502/6510/6509/7501/8500 instruction
147
Set
Appendix B
Some Characteristics of Commodore
155
Machines
IWlCiwI III Iww
Mppenaix w
Moinnrv Mans
167
MppenijiA u
Oharflct^r Sets
241
Appenaix c
Fvorri^efi for Alternative Commodore
251
il/iachines
AoDendix F
Floating Point Representation
277
Appendix G
Uncrashing
279
Appendix H
Supermon Instructions
283
Appendix 1
lA Chip Information
293
Appendix J
Disk User's Guide
357
Glossary
365
index
371
vi
Note to Readers
This book introduces beginners to the principles of machine language: what it
is, how it works, and how to program with it.
It is based on an intensive two-day course on machine language that has been
presented many times over the past five years.
Readers of this book should have a computer on hand: students will learn by
doing, not just by reading. Upon completing the tutorial material in this book, the
reader will have a good idea of the fundamentals of machine language. There will
be more to be learned; but by this time, students should understand how to adapt
other material from books and magazines to their own particular computers.
LIMITS OF LIABILITY AND
DISCLAIMER OF WARRANTY
The author and publisher of this book have used their best efforts in preparing
this book and the programs contained in it. These efforts include the development,
research, and testing of the programs to determine their effectiveness. The author
and the publisher make no warranty of any kind, expressed or implied, with regard
to these programs, the text, or the documentation contained in this book. The
author and the publisher shall not be liable in any event for claims of incidental
or consequential damages in connection with, or arising out of, the furnishing,
performance, or use of the text or the programs.
Note for Commodore 128 Owners
The Commodore 1 28 is three machines in one: a Commodore 64, a Commodore
128, and a CP/M machine. You may select any of the three at any time.
If you choose the Commodore 64 mode, you'll find examples within this book
that will work on your machine. The programs you write will be compatible with
other ("real") Commodore 64 computers. But you'll lose access to extra memory
and to other features of the new machine. In particular, you won't have a built-in
machine language monitor and will need to load one from tape or disk.
If you choose the Commodore 128 mode, you're working with a richer and more
powerful machine. You will have a built-in machine language monitor for speed
and convenience, and access to new features such as 80 columns, with extra
complexity. There are new rules to be learned. This book contains extra material
to enable you to cope with the new features of the CI 28.
If you choose CP/M mode, you will be in an environment that is quite different
from other Commodore machines. This book, working with the 64 or 1 28 mode,
can teach you principleis of machine language and skills which may be carried to
other computer environments, including CP/M. But it will not teach you CP/M itself
or CP/M's machine language.
vii
A Commodore 128 owner can read each chapter of this book twice, if desired.
The first time, the exercises for the Commodore 64 can be worl<ed through; the
second time, those for the 128 can be used. The principles are the same; the
code is similar; but the 128 often calls for a little more detailed worl<.
If you wish to learn machine language for the Commodore 128, please read the
Introduction in Appendix E, under Exercises for the Commodore 128. It will give
you some starting facts about your machine. There is more information on the
128 in the latter section of Appendix B and elsewhere, but don't try to read it all
at the start. It will be there when you need it.
viii
Preface
This book is primariiy tutorial in nature. It contains, however, extensive reference
material, which the reader will want to continue to use.
No previous machine language experience is required. It is useful if the reader
has had some background in programming in other languages, so that concepts
such as loops and decisions are understood.
Beginners will find that the material in this book moves at a fast pace. Stay with
it; if necessary, skip ahead to the examples and then come back to reread a difficult
area.
Readers with some machine language experience may find some of the material
too easy; for example, they are probably quite familiar with hexadecimal notation
and don't need to read that part. If this is the case, skip ahead. But do enter all
the programming projects; if you have missed a point, you may spot it while doing
an exercise.
Programming students learn by doing. The beginner needs to learn simple things
about his or her machine in order to feel in control. The elements that are needed
may be itemized as:
• Machine language. This is the objective, but you can't get there without the
next two items.
• Machine architecture. All the machine language theory in the world will have
little meaning unless the student knows such things as where a program may
be placed in memory, how to print to the screen, or how to input from the
keyboard.
• Machine language tools. The use of a simple machine language monitor to
read and change memory is vital to the objective of making the computer do
something in machine language. Use of a simple assembler and elements of
debugging are easy once you know them; but until you know them, it's hard
to make the machine do anything.
Principles of sound coding are important. They are seldom discussed explicitly,
but run as an undercurrent through the material. The objective is this: it's easy to
do things the right way, and more difficult to do them the wrong way. By introducing
examples of good coding practices early, the student will not be motivated to look
for a harder (and inferior) way of coding.
It should be pointed out that this book deals primarily with machine language,
not assembly language. Assembler programs are marvellous things, but they are
ix
too advanced for the beginner. I prefer to see the student forming an idea of how
the bytes of the program lie within memory. After this concept is firmly fixed in
mind, he or she can then look to the greater power and flexibility offered by an
assembler.
X
Acknowledgements
Thanks go to Elizabeth Deal for acting as resource person in the preparation
of this book. When I was hard to find, the publisher could call upon Elizabeth for
technical clarification.
xi
Introduction
Why learn machine language? There are three reasons. First, for speed; ma-
chine language programs are fast. Second, for versatility; all other languages are
limited in some way, but not machine language. Third, for comprehension; since
the computer really works in machine language only, the key to understanding
how the machine operates is machine language.
Is it hard? Not really. It's finicky, but not difficult. Individual machine language
instructions don't do much, so we need many of them to do a job. But each
instruction is simple, and anyone can understand it if he or she has the patience.
Some programmers who started their careers in machine language find "higher
level" languages such as BASIC quite difficult by comparison. To them, machine
language instructions are simple and precise, whereas BASIC statements seem
vague and poorly defined by comparison.
Where will this book take you? You will end up with a good understanding of
what machine language is, and the principles of how to program in it. You won't
be an expert, but you'll have a good start and will no longer be frightened by this
seemingly mysterious language.
Will the skills you learn be transportable to other machines? Certainly. Once
you understand the principles of programming, you'll be able to adapt. If you were
to change to a non-Commodore machine that used the 6502 chip (such as Apple
or Atari), you'd need to learn about the architecture of these machines and about
their machine language monitors. They would be different, but the same principles
would apply on all of them.
Even if you change to a computer that doesn't use a chip from the 6502 family,
you will be able to adapt. As you pick through the instructions and bits of the
Commodore machine, you will have learned about the principles of all binary
computers. You will need to learn the new microprocessor's instruction set, but it
will be much easier the second time around.
Do you need to be a BASIC expert before tackling machine language? Not at
all. This book assumes you know a little about programming fundamentals: loops,
branching, subroutines, and decision making. But you don't need to be an ad-
vanced programmer to learn machine language.
xiii
1
First
Concepts
This cliapter discusses:
• Tile inner worl<ings of microcomputers
• Computer notation: binary and hexadecimal
• The 650x's inner architecture
• Beginning use of a machine language monitor
• A computer's "memory layout"
• First machine language commands
• Writing and entering a simple program
1
2
MACHINE LANGUAGE FOR COMMODORE MACHINES
The Inner Workings of Microcomputers
All computers contain a large number of electrical circuits. Within any
binary computer, these circuits may be in only two states: "on" or "off."
Technicians will tell you that "on" usually means full voltage on the circuit
concerned, and "off" means no voltage. There's no need for volume control
adjustments within a digital computer: each circuit is either fully on or fully
off.
The word "binary" means "based on two," and everything that happens
within the computer is based on the two possibilities of each circuit: on or
off. We can identify these two conditions in any of several ways:
ON or OFF
TRUE or FALSE
YES or NO
1 orO
The last description, 1 or 0, is quite useful. It is compact and numeric. If
we had a group of eight circuits within the computer, some of which were
"on" and others "off," we could describe their conditions with an expression
such as:
llDDDlll
This would signify that the two leftmost wires were on, the next three off,
and the remaining three on. The value 11000111 looks like a number; in
fact, it is a binary number in which each digit is or 1 . It should not be
confused with the equivalent decimal value of slightly over 1 1 million; the
digits would look the same, but in decimal each digit could have a value
from to 9. To avoid confusion with decimal numbers, binary numbers
are often preceded by a percent sign, so that the number might be shown
as ^liiaODlll .
Each digit of a binary number is called a bit, which is short for "binary
digit." The number shown above has eight bits; a group of eight bits is a
byte. Bits are often numbered from the right, starting at zero. The right-
hand bit of the above number would be called "bit 0," and the left-hand
bit would be called "bit 7." This may seem odd, but there's a good math-
ematical reason for using such a numbering scheme.
FIRST CONCEPTS
3
The Bus
It's fairly common for a group of circuits to be used together. The wires
run from one microchip to another, and then on to the next. Where a group
of wires are used together and connect to several different points, the
group is called a bus (sometimes spelled "buss").
The PET, CBM, and VIC-20 use a microprocessor chip called the 6502.
The Commodore 64 uses a 6510. The Commodore B series uses a 6509
chip, and the Commodore PLUS/4 uses a chip called 7501 . All these chips
are similar, and there are other chips in the same family with numbers like
6504; every one works on the same principles, and we'll refer to all of
them by the family name 650x.
Let's take an example of a bus used on any 650x chip. A 650x chip has
little built-in storage. To get an instruction or perform a computation, the
650x must call up information from "memory"— data stored within other
chips.
The 650x sends out a "call" to all memory chips, asking for information.
It does this by sending out voltages on a group of sixteen wires called the
"address bus." Each of the sixteen wires may carry either voltage or no
voltage; this combination of signals is called an address.
Every memory chip is connected to the address bus. Each chip reads the
address, the combination of voltages sent by the processor. One and only
one chip says, "That's me!" In other words, the specific address causes
650x
1
1 1 1
\
1 1 1
1
1 1 1
MEMORY
CHIP
MEMORY
Figure 1.1 Address bus connecting 650x & 3 chips
4
MACHINE LANGUAGE FOR COMMODORE MACHINES
that chip to be selected; it prepares to communicate with the 650x. All
other chips say, "That's not me!" and will not participate in data transfer.
The Data Bus
Once the 650x microprocessor has sent an address over the address bus
and it has been recognized by a memory chip, data may flow between
memory and 650x. This data is eight bits (it flows over eight wires). It
might look like this:
□IDllDll
The data might flow either way. That is, the 650x might read from the
memory chip, in which case the selected memory chip places information
onto the data bus which is read by the microprocessor. Alternatively, the
650x might wish to write to the memory chip. In this case, the 650x places
information onto the data bus, and the selected memory chip receives the
data and stores it.
650x
-ADDRESS BUS-
DATA BUS
III
MEMORY
CHIP
("SELECTED")
MEMORY
CHIP
(NOT
SELECTED)
MEMORY
CHIP
(NOT
SELECTED)
Figure 1.2 Two-way data bus
All other chips are still connected to the data bus, but they have not been
selected, so they ignore the information.
The address bus is accompanied by a few extra wires (sometimes called
FIRST CONCEPTS
5
the control bus) that control such things as data timing and the direction
in which the data should flow: read or write.
Number Ranges
The address bus has sixteen bits, each of which might be on or off. The
possible combinations number 65536 (two raised to the sixteenth power).
We then have 65536 different possibilities of voltages, or 65536 different
addresses.
The data bus has eight bits, which allows for 256 possibilities of voltages.
Each memory location can store only 256 distinct values.
It is often convenient to refer to an address as a decimal number. This is
especially true for PEEK and POKE statements in the BASIC language.
We may do this by giving each bit a "weight." Bit zero (at the right) has
a weight of 1; each bit to the left has a weight of double the amount, so
that bit 15 (at the left) has a weight of 32768. Thus, a binary address such
as
□DDIODIOIDIDIIDD
has a value of 4096 + 512 + 128 + 32 + 8 + 4 or 4780. A POKE to 4780
decimal would use the above binary address to reach the correct part of
memory.
128
64
32
16
8
4
2
1
EIGHT BITS
32768
16384
8192
4096
2048
1024
512
256
777-.
128
64
^77
32
16
7
8
4
u
2
1
SIXTEEN BITS
Figure 1.3
Direct conversion between decimal and binary is seldom needed. Such
conversions usually pass through an intermediate number system, called
hexadecimal.
Hexadecimal Notation
Binary is an excellent system for the computer, but it is inconvenient for
most programmers. If one programmer asks another, "What address should
6
MACHINE LANGUAGE FOR COMMODORE MACHINES
I use for some activity?", an answer sucli as "Address
^□□DIDDIDIOIOIIDD" might be correct but would probably be un-
satisfactory. There are too many digits.
Hexadecimal is a code used by humans to conveniently represent binary
numbers. The computer uses binary, not hexadecimal; programmers use
hexadecimal because binary is cumbersome.
To represent a binary number in hexadecimal, the bits must be grouped
together four at a time. If we take the binary value given above and split
it into groups of four, we get
□ ODl HDD
Now each group of four bits is represented by a digit as shown in the
following table:
DDDO-Q nma-A inao-a iidq-c
□□01-1 OlDl-S l^Dl-R llDl-D
DllQ-t l^lQ-a lllQ-E
□011-3 □111-? IDll-B 1111-F
Thus, the number would be represented as hexadecimal 12 AC. A dollar
sign is often prefixed to a hexadecimal number so that it may be clearly
recognized:$lEAC.
The same type of weighting is applied to each bit of the group of four as
was described before. In other words, the rightmost bit (bit zero) has a
weight of 1 , the next left a weight of 2, the next a weight of 4, and the
leftmost bit (bit three) a weight of 8. If the total of the weighted bits exceeds
nine, an alphabetic letter is used as a digit: A represents ten; B, eleven;
C, twelve; and F, fifteen.
Eight-bit numbers are represented with two hexadecimal digits. Thus,
^OlQllOll may be written as $53.
Hexadecimal to Decimal
As we have seen, hexadecimal and binary numbers are easily inter-
changeable. Although we will usually write values in "hex," occasionally
we will need to examine them in their true binary state to see a particular
information bit.
Hexadecimal isn't hard to translate into decimal. You may recall that in
early arithmetic we were taught that the number 24 meant, "two tens and
four units." Similarly, hexadecimal 24 means "two sixteens and four units,"
or a decimal value of 36. By the way, it's better to say hex numbers as
FIRST CONCEPTS
"two four" rather than "twenty-four," to avoid confusion with decimal val-
ues.
The formal procedure, or algorithm, to go from hex to decimal Is as follows.
Step 1 : Take the leftmost digit; if it's a letter A to F , convert It to the appropriate
numeric value (A equals 10, B equals 11, and so on).
Step 2: If there are no more digits, you're finished; you have the number. Stop.
Step 3: Multiply the value so far by sixteen. Add the next digit to the result,
converting letters if needed. Go back to step 2.
Using the above steps, let's convert the hexadecimal number $15ac.
Step 1: The leftmost digit is 1.
Step 2: There are more digits, so we'll continue.
Step 3. 1 times lb is It, plus E gives Ifl.
Step 2: More digits to come.
Step 3: la times lb is Eflfl, plus ID (for A) gives E^fl.
Step 2: More digits to come.
Step 3: Eqa X lb is -^Tbfl, plus IS (forC)gives <7fl0.
Step 2: No more digits: ^7flD is the decimal value.
This is easy to do by hand or with a calculator.
Decimal to Hexadecimal
The most straightfonward method to convert from decimal to hexadecimal
is to divide repeatedly by 16; after each division, the remainder is the next
hexadecimal digit, working from right to left. This method is not too well
suited to small calculators, which usually don't give remainders. The fol-
lowing fraction table may offer some help:
. .ESDD-A .50DD-fl .750D-C
.□bE5-l .31E5-5 .5t25-q .fll25-D
.155D-E .375D-fc .t55D-ft .fl75D-E
.lfl75-3 .-^375-7 .tfi75-B .q375-F
If we were to translate 4780 using this method, we would divide by 16,
giving 298.75. The fraction tells us the last digit is C; we now divide 298
by 16, giving 18.625. The fraction corresponds to A, making the last two
digits AC. Next we divide 18 by 16, getting 1.125— now the last three
digits are 2 AC. We don't need to divide the one by 16, although that would
work; we just put it on the front of the number to get an answer of $ 1 E AC.
There are other methods of performing decimal-to-hexadecimal conver-
8
MACHINE LANGUAGE FOR COMMODORE MACHINES
sions. You may wish to look them up in a book on number systems.
Altematively, you may wish to buy a calculator that does the job electron-
ically. Some programmers get so experienced that they can do conver-
sions in their heads; I call them "hex nuts."
Do not get fixed on the idea of numbers. Memory locations can always
be described as binary numbers, and thus may be converted to decimal
or hexadecimal at will. But they may not mean anything numeric: the
memory location may contain an ASCII coded character, an instruction,
or any of several other things.
Memory Elements
There are generally three types of devices attached to the memory busses
(address, data, and control busses):
• RAM: Random access memory. This is the read and write memory, where
we will store the programs we write, along with values used by the program.
We may store information into RAM, and may recall the information at any
time.
• ROM: Read only memory. This is where the fixed routines are kept within the
computer. We may not store information into ROM; its contents were fixed
ADDRESS BUS
650x
MEMORY BUS
RAM
(READ
AND
WRITE)
ROM
(READ
ONLY)
lA
(SPECIAU
CONNECTIONS
TO "OUTSIDE WORLD'
Figure 1.4
FIRST CONCEPTS
9
when the ROM was made. We will use program units (subroutines) stored in
ROM to do special tasks for us, such as input and output.
• I A: Interface adaptor chips. These are not memory in the usual sense; but,
these chips are assigned addresses on the address bus, so we call them
"memory-mapped" devices, information may be passed to and from these
devices, but the information is generally not stored in the conventional sense.
I a chips contain such functions as: input/output (I/O) Interfaces that serve
as connections to the "outside world"; timing devices; Interrupt control sys-
tems; and sometimes specialized functions, such as video control or sound
generation. I ft chips come in a wide variety of designs, Including the PI ft
(peripheral Interface adaptor), the VIA (versatile Interface adaptor), the Clft
(complex Interface adaptor), the VIC (video interface chip), and the SID
(sound Interface device).
Within a given computer, some addresses may not be used at all. Some
devices may respond to more tlian one address, so tliat tfiey seem to be
in two places in memory.
An address may be tliought of as split in two parts. One part, usually the
high part of the address, selects the specific chip. The other part of the
address selects a particular part of memory within the chip. For example,
in the Commodore 64, the hex address $DD2D (decimal 53EflD) sets
the border color of the video screen. The first part of the address (roughly,
$DD . . .) selects the video chip; the last part of the address (. . . ED)
selects the part of the chip that controls border color.
Microprocessor Registers
Within the 650x chip are several storage areas called registers. Even
though they hold information, they are not considered "memory" since
they don't have an address. Six of the registers are important to us. Briefly,
they are:
PC: (16 bits) The program counter tells where the next
instruction will come from.
A, X and Y (8 bits each) These registers hold data.
SR The status register, sometimes called PSW
(processor status word), tells about the re-
sults of recent tests, data handling, and so
on.
S P The stack pointer keeps track of a temporary
storage area.
We will talk about each of these registers in more detail later. At the
moment, we will concentrate on the PC (program counter).
10 MACHINE LANGUAGE FOR COMMODORE MACHINES
ADDRESS BUS
DATA BUS
650x CHIP
Figure 1.5
Instruction Execution
Suppose that the 650x is stopped (not an easy trick), and that there is a
certain address, say $1534 , in the PC. The moment we start the micro-
computer, that address will be put out to the address bus as a read address,
and the processor will add one to the value in the PC.
Thus, the contents of address $123 A will be called for, and the PC will
change to $1535. Whatever information comes in on the data bus will
be taken to be an instruction.
The microprocessor now has the instruction, which tells it to do something.
The action is performed, and the whole action now repeats for the next
PC
$1234 1
ADDRESS
BUS
PC
1 $1235
$1234
INSTRUCTION ^
ADDRESS
BUS
DATA BUS
Figure 1.6
FIRST CONCEPTS
11
instruction. In other words, address $1235 will be sent to memory, and
the PC will be incremented to $153 1.
You can see that the processor works in the same way that most computer
languages do: an instruction is executed, and then the computer proceeds
to the next instruction, and then the next, and so on. We can change the
sequence of execution by means of a "jump" or "branch" to a new location,
but normally, it's one instruction after another.
Data Registers: A, X, and Y
Any of three registers can be used to hold and manipulate eight bits of
data. We may load information from memory into A, X, or Y; and we may
store information into memory from any of A, X, or Y.
Both "load" and "store" are copying actions. If I load A (LDA) from
address $E3<5, I make a copy of the contents of hex E3<5 into A; but
E3AS still contains its previous value. Similarly, if I store Y into $3^ St.,
I make a copy of the contents of Y into that address; Y does not change.
The 650x has no way of moving information directly from one memory
address to another. Thus, this information must pass via A, X, or Y; we
load it from the old address, and store it to the new address.
Later, the three registers will take on individual identities. For example,
the A register is sometimes called the accumulator, since we perform
addition and subtraction there. For the moment, they are interchangeable:
we may load to any of the three, and we may store from any of them.
First Program Project
C128 note: The programming task that follows will need to be slightly
changed if you are using a Commodore 128 in C128 mode. In particular,
the program will need to be written into a different part of memory from
that which Is shown below. Check Appendix E, Exercises for the Com-
modore C128, page 251 for the correct CI 28 coding. ^ n r, o
Here's a programming task: locations $0330 and $D3fll contain in-
formation. We wish to write a program to exchange the contents of the
two locations. How can we do this?
We must make up a plan. We know that we cannot transfer information
directly from memory to memory. We must load to a register, and then
store. But there's more. We must not store and destroy data in memory
until that data has been safely put away. How can we do this?
MACHINE LANGUAGE FOR COMMODORE MACHINES
Here's our plan. We may load one value into A (say, the contents of
$ 3 a 0), and load the other value into X (the contents of $ □ 3 fl 1). Then
we could store a and X back, the other way around.
We could have chosen a different pair of registers for our plan, of course:
A and Y, or X and Y. But let's stay with the original plan. We can code
our plan in a more formal way:
LDA $0360 (bring in first value)
LDX $0351 (bring in second value)
STft $03fll (store in opposite place)
STX $D3flD (and again)
You will notice that we have coded "load A" as LDA, "load X" as
LDX, "store A" asSTA,and "store X" as STX. Every command
has a standard three-letter abbreviation called a mnemonic. Had we used
the Y register, we might have needed to use LDY and STY.
One more command is needed. We must tell the computer to stop when
it has finished the four instructions. In fact, we can't stop the computer;
but if we use the command BRK (break), the computer will go to the
machine language monitor (MLM) and wait for further instructions. We'll
talk about the MLM in a few moments.
We have written our program in a notation styled for human readability,
called assembly language. But the computer doesn't understand this no-
tation. We must translate it to machine language.
The binary code for LDA is ^IDlOllDl, or hexadecimal AD. That's
what the computer recognizes; that's the instruction we must place in
memory. So we code the first line:
AD flO 03 LDA $D3flO
It's traditional to write the machine code on the left, and the source code
on the right. Let's look closely at what has happened.
LDA has been translated into $AD. This is the operation code, or op
code, which says what to do. It will occupy one byte of memory. But we
need to follow the instruction with the address from which we want the
load to take place. That's address $D3flD; it's sixteen bits long, and so
it will take two bytes to hold the address. We place the address of the
instruction, called the operand, in memory immediately behind the instruc-
tion. But there's a twist. The last byte comes first, so that address $ □ 3 a □
is stored as two bytes: fiO first and then D3.
FIRST CONCEPTS
13
1
This method of storing addresses — low byte first — is standard in the 650x.
It seems unusual, but it's there for a good reason. That is, the computer
gets extra speed from this "backwards" address. Get used to It; you'll see
it again, many times.
Here are some machine language op codes for the instructions we may
use. You do not need to memorize them.
LDfl-aD LDX-fiE LDY-aC BRK-DD
STA-flD STX-flE STY-aC
Now we can complete the translation of our program.
AD
ao
03
LDA
$D3aD
A£
ai
03
LDX
$D3fll
flD
ai
03
STA
$D3ai
as
an
03
STX
$03aD
□ □
BRK
On the right, we have our plan. On the left, we have the actual program
that will be stored in the computer. We may call the right side assembly
code and the left side machine code, to distinguish between them. Some
users call the right-hand information source code, since that's where we
start to plan the program, and the left-hand program object code, since
that's the object of the exercise— to get code into the computer. The job
of translating from source code to object code is called assembly. We
performed this translation by looking up the op codes and translating by
hand; this is called hand assembly.
The code must be placed into the computer. It will consist of 13 bytes:
AD ao 03 AE ai 03 ao ai d3 aE ao 03 oo. That's the
whole program. But we have a new question: where do we put It?
Choosing a Location
We must find a suitable location for our program. It must be placed into
RAM memory, of course, but where?
For the moment, we'll place our program into the ^ssette buffer , starting
at address $D33C (decimal a 2 a). That's a goodplace to puTshort test
programs, which is what we will be writing for a while.
^ $0600 dz^jmxl ^814
Now that we've made that decision, we face a new hurdle: how do we get
the program in there? To do that, we need to use a machine language
monitor.
14
MACHINE LANGUAGE FOR COMMODORE MACHINES
Monitors: What They Are
All computers have a built-in set of programs called an operating system
that gives the machine its style and basic capabilities. The operating sys-
tem tal<es care of communications — reading the l<eyboard, mal<ing the
proper things appear on the screen, and transferring data between the
computer and other devices, such as disk, tape, or printer.
When we type on the computer keyboard, we use the operating system,
which detects the characters we type. But there's an extra set of programs
built into the computer that must decide what we mean. When we are
using the BASIC language, we'll be communicating with the BASIC mon-
itor, which understands BASIC commands such as NEW, LOAD, LIST,
or BUN. It contains editing features that allow us to change the BASIC
program that we are writing.
But when we switch to another system — often another language — we'll
need to use a different monitor. Commands such as NEW or LIST don't
have any meaning for a machine language program. We must leave the
BASIC monitor and enter a new environment: the machine language mon-
itor. We'll need to learn some new commands because we will be com-
municating with the computer in a different way.
The Machine Language Monitor
Most PET/CBM computers have a simple MLM (machine language mon-
itor) built in. It may be extended with extra commands. The Commodore
PLUS/4 contains a very powerful MLM. The VIC-20 and Commodore 64
do not have a built-in MLM, but one can be added. Such a monitor may
be either loaded into RAM or plugged in as a cartridge. Monitors may be
purchased or obtained from User clubs.
Most machine language monitors work in a similar way, and have about
the same commands. To proceed, you'll need an MLM in your computer.
Use the built-in one, plug it in, load it in, or load and run . . . whatever the
instructions tell you. On a PET/CBM machine, typing the command SYS
A will usually switch you to the built-in monitor. After an MLM has been
added to a VIC or Commodore 64, the command SYS fl will usually get
you there. On the Commodore PLUS/4, the BASIC command MONITOR
will bring the monitor into play.
FIRST CONCEPTS
15
C128 note: When the Commodore 128 is in C64 mode, it needs to have
a monitor program loaded, as does the Commodore 64. When in the C128
mode, however, the command MONITOR wili bring the monitor into piay
There wili be slight differences in the screen display of this monitor. Ap
pendix H contains information on the various monitor commands and
formats.
Caution: Occasionally, you may run across a monitor which uses— and
changes — memory locations in the address range $D33C to $D3FD,
which is where we will put many of our programs. There is a version of
program MICROMON which does this. Such a monitor will create problems
for us as we try to work the following examples, since our programs and
data will be changed by the monitor as we use it. The built-in monitors
will certainly not have any problem. If you encounter any problems with
the following examples, and it appears that your program is being mys-
teriously changed, switch to another machine language monitor.
Monitor Display
The moment you enter the ML M, you'll see a display that looks somethino
like this:
B*
PC SR ftC XR YR SP
□ □□5 50 SA 23 tfi Ffl
The cursor will be flashing to the right of the period on the bottom line.
The exact appearance of the screen information may vary according to
the particular monitor you are using. Other material may be displayed—
in particular, a value called IRQ— which we will ignore for the time being.
The information you see may be interpreted as follows:
B*— we have reached the MLM by means of a "break." More about that later.
PC— The value shown below this title is the contents of the program counter.
This indicates where the program "stopped." In other words, if the value shown
is address DUOS, the program stopped at address DDD^, since the PC is
ready to continue at the following address. The exact value (ODD A versus
□ □□5) may vary depending on the particular MLM.
S R— The value shown below shows the status register, which tells us the results
of recent tests and data operations. We'd need to split apart the eight bits and
look at them individually to establish all the information here; we will do this at
a later time.
76
MACHINE LANGUAGE FOR COMMODORE MACHINES
ftC, XR, and YR— The values shown below these three titles are the contents
of our three data registers: R, X, and Y.
SP— The value shown below is that of the stack pointer, which Indicates a
temporary storage area that the program might use. A value of F fl , for example,
tells us that the next item to be dropped into the stack area would go to address
$□ IF fl in memory. More on this later.
You will notice that the display printed by the monitor (called the register
display) shows the internal registers within the 650x chip. Sometimes there
is another item of information, titled IRQ, in this display. It doesn't belong,
since it does not represent a microprocessor register. IRQ tells us to what
address the computer will go if an interrupt occurs; this information is
stored in memory, not within the 650x.
M L M Commands
The machine language monitor is now waiting for you to enter a command.
The old BASIC commands don't work any more; LIST or NEW or SYS
are not known to the MLM. We'll list some popular commands in a moment.
First, let's discuss the command that takes us back to BASIC.
X exits the MLM and returns to the BASIC monitor. Try it. Remember
to press RETURN after you've typed the X, of course. You will return to
the BASIC system, and the BASIC monitor will type READY. You're back
in familiar territory. Now go back to the monitor with SYS^orSYSflor
MONITOR as the case may be. BASIC ignores spaces: it doesn't matter
if you type SYSflorSYS fl; just use the right number for your machine
(A for PET/CBM, fl for VIC/64).
Remember: BASIC commands are no good in the MLM, and machine
language monitor commands (such as X) are no good in BASIC. At first,
you'll give the wrong commands at the wrong time because it's hard to
keep track of which monitor system is active. If you type in an MLM
command when you're in BASIC, you'll probably get a ? SYNTAX ERROR
reply. If you type in a BASIC command when you're in the machine lan-
guage monitor, you'll probably get a question mark in the line you typed.
Some other MLM commarids are as follows:
M IDID (display memory from hex 1 □ □ □ to
!□!□)
R (display registers . . . again!)
FIRST CONCEPTS
17
G □ 3 3 C (go to D 3 3 C and start running a
program)
Do not enter this last (G) command. There is no program at address
$03 3C yet, so the computer would execute random instructions and we
would lose control.
There are two other fundamental instructions that we won't use yet: they
are S for save and L for load. These are tricky. Until you learn about
BASIC pointers (Chapter 6), leave them alone.
Displaying Memory Contents
You'll notice that there is a command for displaying the contents of mem-
ory, but there doesn't seem to be one for changing memory. You can do
both, of course.
Suppose we ask to display memory from $lDDOto$lDlD with the
command
Be careful that you have exactly one space before each address. You
might get a display that looks something like this:
.:1DDD 11 3A E< OD 51 3E DA kk
.rlDDfl 50 Ak <q AJ) ED A2 55 5A
.:1D1D SA AS 52 Ah A^ AS AC AA
C128 note: The above display will differ slightly if you are using C128.
The section Exercises for the Commodore 128, in Appendix E, gives
details.
The four-digit number at the start of each line represents the address in
memory being displayed. The two-digit numbers to the right represent the
contents of memory. Keep in mind that all numbers used by the machine
language monitor are hexadecimal.
In the example above, $ 1 □ □ □ contains a value of$ll;$iaai contains
a value of $3 A; and so on, until $1DD7, which contains a value of $kk.
We continue with address $!□□ & on the next line. Most monitors show
eight memory locations on each line, although some VIC-20 monitors show
only five because of the narrow screen.
We asked for memory locations up to address $ 1 D 1 D only; but we get
the contents of locations up to $1D17 in this case. The monitor always
fills out a line, even if you don't ask for the extra values.
18
MACHINE LANGUAGE FOR COMMODORE MACHINES
Changing Memory Contents
Once we have displayed the contents of part of memory, we can change
that part of memory easily. All we need to do is to move the cursor until
it is positioned over the memory contents in question, type over the value
displayed, and then press BETUBN.
This is quite similar to the way BASIC programs may be changed; you
may type over on the screen, and when you press BET URN, the new line
replaces the old. The general technique is called screen editing.
If you have displayed the contents of memory, as in the example above,
you might like to change a number of locations to zero. Don't forget to
strike BETUBN so that the change on the screen will take effect in mem-
ory. Give another M memory display command to confirm that memory
has indeed been changed.
Changing Registers
We may also change the contents of registers by typing over and pressing
BETUBN. You may take a register display with command B, and then
change the contents of PC, AC, XR, and YB. Leave the contents of SB
and SP unchanged — tricky things could happen unexpectedly if you ex-
periment with these two.
Entering the Program
C128 note: Remember to check Exercises for the Commodore 128, in
Appendix E, for the appropriate code.
We might rewrite our program one last time, marking in the addresses
that each instruction will occupy. You will recall that we have decided to
put our program into memory starting at address $0B3C (part of the
cassette buffer).
□33C AD 50 03 LDR $D3flO
□33F AE fll 03 LDX $D3fll
Q3AE flD fll 03 STA $D3fll
□3<5 flE flD 03 STX $D3flD
U3A& UU
FIRST CONCEPTS
79
Remember that most of the above listing is cosmetic. The business end
of the program is the set of two-digit hex numbers shown to the left. At
the extreme left, we have addresses— that's information, but not the pro-
gram. At the right, we have the "source code"— our notes on what the
program means.
How do we put it in? Easy. We must change memory. So, we go to the
MLM, and display memory with
M 0330 03A5
We might have anything in that part of memory, but we'll get a display
that looks something like
.:D33C XX XX xx xx xx xx xx xx
.:D3AA XX XX XX xx xx xx xx xx
You won't see "xx," of course; there will be some hexadecimal value
printed for each location. Let's move the cursor back and change this
display so that it looks like this:
•:D33C AD flD D3 AE fll 03 flD fll
.:Q3AA Q3 flE flD 03 □□ xx xx xx
Don't type in the "xx"— just leave whatever was there before. And be
sure to press RETURN to activate each line; if you move the cursor down
to get to the next line without pressing RETURN, the memory change
would not happen.
Display memory again (M 0330 034 fl) and make sure that the
program is in place correctly. Check the memory display against the pro-
gram listing, and be sure you understand how the program is being tran-
scribed into memory.
If everything looks in order, you're ready to run your first machine language
program.
Preparation
There's one more thing that we need to do. If we want to swap the contents
of addresses $03flD and $0361, we'd better put something into those
two locations so that we'll know that the swap has taken place correctly.
Display memory with M □3flD □3fll and set the resulting display
so that the values are
.:D3flO 11 XX XX xx xx xx xx
20
MACHINE LANGUAGE FOR COMMODORE MACHINES
Remember to press RETURN. Now we may run our program; we start it
up with
G 033C
The program runs so quicl<ly that it seems instantaneous (the run time is
less than one fifty thousandth of a second). The last instruction in our
program was BRK for break, and that sends us straight to the MLM with
a display of *B (for breal<, of course) plus all the registers.
Nothing seems to have changed. But wait. Look carefully at the register
display. Can you explain the values you see in the AC and XR registers?
Can you explain the PC value?
Now you may display the data values we planned to exchange. Give the
memory display command M 0330 □361— have the contents of
the two locations changed?
They'd better have changed. Because that's what the writing of our pro-
gram was all about.
Things You Have Learned
— Computers use binary. If we want to work with the inner fabric of the computer,
we must come to terms with binary values.
—Hexadecimal notation is for humans, not for computers. It's a less clumsy
way for people to cope with binary numbers.
—The 650x microprocessor chip communicates with memory by sending an
address over its memory bus.
— The 650x has internal work areas called registers.
— The program counter tells us the address from which the processor will get
its next instruction.
—Three registers, called A, X, and Y, are used to hold and manipulate data.
They may be loaded from memory, and stored Into memory.
—Addresses used in 650x Instructions are "flipped:" the low byte comes first,
followed by the high byte.
— The machine language monitor gives us a new type of communications path
into the computer. Among other things, it allows us to inspect and change
memory in hexadecimal.
Detail: Program Execution
When we say G 033C to start up our program, the microprocessor goes
through the following steps:
FIRST CONCEPTS
21
1. It asks for the contents of $033C; it receives SAD, which it recognizes as
the op code " load ft , " It realizes that it will need a two-byte address to
go with this instruction.
2. It asks for the contents of $03 3D, and then $033E. As it receives the
values of $ao and $03 it gathers them into an "instruction address."
3. The microprocessor now has the whole instruction. The PC has moved along
to $ 3 3 F . The 650x now executes the instruction. It sends address $0360
to the address bus; when it gets the contents (perhaps $11), it delivers this
to the R register. The A register now contains $11.
4. The 650x is ready to take on the next instruction; the address $033F goes
from the PC out to the address bus; and the program continues.
Questions and Projects
Do you know that your computer has a part of memory called "screen
memory"? Whatever you put Into that part of memory appears on the
screen. You'll find this described in BASIC texts as "screen POKE-ing."
The screen on the PET/CBM is at SflDDD and up; on the VIC, it's often
(but not always) at $1EDD and up; on the Commodore 64, it's usually at
$ □ ; and on the PLUS/4, it may be found at $ □ C □ □ . With the C1 28,
the 40-column screen is at $ □ □, but If you are in the 80-column mode,
the screen is not mapped directly to memory.
If you write a program to store information in the screen memory address,
the appropriate characters will appear on the screen. You might like to try
this. You can even "swap" characters around on the screen, if you wish.
Two pitfalls may arise. First, you might write a perfect program that places
information near the top of the screen; then, when the program finishes,
the screen might scroll, and the results would disappear. Second, the VIC
and Commodore 64 use color, and you might inadvertently produce white-
on-white characters; these are hard to see.
Here's another question. Suppose I asked you to write a program to move
the contents of five locations, $D3fiD to $D3fl^, in an "end-around"
fashion, so that the contents of $0360 moved to$D3fll, $D3fllto
$D3fl2, and so on, with the contents of $Q3&A moved to $03fiD. At
first glance, we seem to have a problem: we don't have five data registers,
we have only three (A, X, and Y). Can you think of a way of doing the
job?
This chapter discusses:
• Calling machine language subroutines
• Trite PRINT subroutine
• immediate addressing
• Calling machine language from BASIC
• Tiny assembler programs
• Indexed addressing
• Simple loops
• Disassembly
24
MACHINE LANGUAGE FOR COMMODORE MACHINES
Calling Machine Language Subroutines
In BASIC, a "package" of program statements called a subroutine may
be brought into action with a GOSUB command. The subroutine ends with
a RETURN statement, which causes the program to return to the calling
point, i.e., the statement immediately following GOSUB.
The same mechanism is available in machine language. A group of in-
structions may be invoked with a juntp subroutine (JSR) command. The
650x goes to the specified address and performs the instructions given
there until it encounters a return from subroutine (RTS) command, at
which time it resumes execution of instructions at the calling point: the
instruction immediately following JSR.
For example, if at address $D33C I code the instruction JSR $153^,
the 650x will change its PC to $1234 and start to take instructions from
that address. Execution will continue until the instruction RTS is encoun-
tered. At this time, the microprocessor would switch back to the instruction
following the JSR, which in this case would be address $D33F (the JSR
instruction is three bytes long).
As in BASIC, subroutines may be "nested;" that is, one subroutine may
call another, and that subroutine may call yet another. We will deal with
subroutine mechanisms in more detail later. For the moment, we'll concern
ourselves with calling prewritten subroutines.
Prewritten Subroutines
A number of useful subroutines are permanently stored in the ROM mem-
ory of the computer. All Commodore machines have a standard set of
subroutines that may be called up by your programs. They are always at the
same addresses, and perform in about the same way regardless of which
Commodore machine is used: PET, CBM, Commodore 64, PHJS/4, Com-
modore 128, or VIC-20. These routines are called the kernel subroutines.
Details on them can be found in the appropriate Commodore reference
manuals, but we'll give usage information here.
The original meaning of the term kernel seems to be lost in legend. It was
originally an acronym, standing for something like "Keyboard Entry Read,
Network and Link." Today, it's just the label we apply to the operating
system that makes screen, keyboard, other input/output and control mech-
anisms work together. To describe this central control system, we might
choose to correct the spelling so as to get the English word, "kernel." For
now, we'll use Commodore's word.
CONTROLLING OUTPUT
25
The three major kernal subroutines that we will deal with in the next few
chapters are shown here:
Address Name What it does
$FFDE CHEOOT Outputs an ASCII character
$FFE< GETIN Gets an ASCII character
$FFE1 STOP Checks the RUN/STOP key
With the first two subroutines, we can input and output data easily. The
third allows us to honor the RON/STOP key, to guard against certain types
of programming error. In this chapter, we'll use CH ROOT to print infor-
mation to the screen.
C H R U T— The Output Subroutine
The CHROUT subroutine at address $FFDE may be used for all types
of output: to screen, to disk, to cassette tape, or to other devices. It's
similar to PRINT and PRINT#, except that it sends only one character.
For the moment, we'll use CHROUT only for sending information to the
computer screen.
Subroutine: CHROUT
Address: $FFDE
Action: Sends a copy of the character in the A register to the
output channel. The output channel is the computer screen
unless arrangements have been made to switch it.
The character sent is usually ASCII (or PET ASCII). When sent to the
screen, all special characters — graphics, color codes, cursor move-
ments—will be honored in the usual way.
Registers: All data registers are preserved during a CHROUT call.
Upon return from the subroutine, A, X, and Y will not have changed.
Status: Status flags may be changed. In the most recent Commodore
machines, the C (carry) flag indicates some type of problem with output.
To print a letter X on the screen, we would need to follow these steps:
1. Bring the ASCII letter X ($5fl) into the A register;
2. JSR to address $FFDE.
26
MACHINE LANGUAGE FOR COMMODORE MACHINES
Why Not POKE?
It may seem that there's an easier way to make things appear on the
screen. We might POKE information directly to screen memory; in ma-
chine language, we would call this a store rather than a POKE, of course.
The moment we change something in this memory area, the information
displayed on the screen will change. Screen memory is generally located
at the following addresses:
PET/CBM: $&□□□ and up (decimal BB7tfi)
Commodore 64 and 1 28: $ □ < □ □ and up (decimal IDEA)
264/364 $□€□□ and up (decimal 307 B)
VIC-20: $1EDD and up (decimal 7 tflD)
The screen memory of the VIC-20 in particular may move around a good
deal, depending on how much additional RftM memory has been fitted.
Occasionally, screen POKEs are the best way to do the job. But most of
the time we'll use the CHROOT, $FFDE subroutine. Here are some of
the reasons why:
• As with PRINT, we won't need to worry about where to place the next
character; it will be positioned automatically at the cursor point.
• If the screen is filled, scrolling will take place automatically.
• Screen memory needs special characters. For example, the character X has
a standard ASCII code of $5a, but to POKE it to the screen we'd need to
use the code $lfl. The CHROOT subroutine uses $53.
• Screen memory may move around, depending on the system and the pro-
gram. The POKE address would need to change; but CHROUT keeps
working.
• Special control characters are honored: $DD for RETURN, to start a new
line; cursor movements; color changes. We can even clear the screen by
loading the screen-clear character ($R3) and calling $FFDB.
• To POKE the screen of the Commodore machines with color, the corre-
sponding color nibble memory must also be POKEd (see the appropriate
memory map in Appendex C). With the subroutine at $FFDE, color is set
automatically.
A Print Project
Let's write some code to print the letter H on the screen. Once again, we'll
use address $ 0330, the cassette buffer, to hold our program. Reminder:
be sure to have your monitor loaded and ready before you start this project.
CONTROLLING OUTPUT
27
First, the plan; we lay out the instructions
LDa #$4fl
We're using a new symbol (#) to signal a special type of information. It
goes by a variety of names: pounds sign, sharp, hash mark, or numbers
sign. A more formal name for the symbol is octothorpe, meaning "eight
points." Whatever you call it, the symbol means "the following information
is not an address, it's a value." In other words, we don't want the computer
to go to address $<fl, we want it to load the A register with the value
$^ a, which represents the ASCII letter H. This type of information access
is called immediate addressing. In other words, take the information im-
mediately, don't go to memory for it.
JSR $FFDE
The previous instruction brought the letter H into the A register; this one
prints it to the screen. Now all we need to do is quit. BEK takes us to the
machine language monitor.
Monitor Extensions
We could repeat the steps of the previous chapter: hand-assembling the
source code into machine language, and then placing it into memory. We
would need to know the instruction codes, and then do a careful translation.
But there's an easier way.
Most machine language monitors contain extra commands to help us do
this type of mechanical translation. We'll use the assembler feature of
these monitors.
Most monitors contain the assemble (A) command. The notable excep-
tion is the built-in monitors within the PET/CBM; these, however, can be
extended by loading in a "monitor extension" program such as Supermen.
The Commodore PLUS/4 series contains an extended monitor, which
includes the A command.
These assemblers are often called nonsymbolic assemblers. This means
that whenever an address is needed, you must furnish that exact address.
You cannot type in a name such as CHROUT and expect the tiny assem-
bler to know what address that represents; instead, you must type $ FFD 5.
C128 note: Remember to check Exercises for the Commodore 128, in
Appendix E, for the appropriate coding, and information on how the CI 28
assembler works.
28
MACHINE LANGUAGE FOR COMMODORE MACHINES
Load your monitor or monitor extension. Do any setup that may be needed.
Tlien type tfie foliowing monitor command:
ft 0330 LDft #$<fl
We are asking tlie computer to assemble (ft) at address $D33C (note
we don't use tlie $ here) the command LDft, Load ft, the immediate value
of $<a, which represents the ASCII letter H. When you press RETURN
after entering this line, the computer may do either of two things:
1 . It may do nothing except print a question mark somewhere on the line. The
question mark Indicates an error in your coding. If the question mark appears
directly after the letter ft, your monitor does not understand the ft assemble
Instruction; get another monitor or properly set up the one you have.
2. Or, it will correctly translate your instruction, and put the object code Into
memory starting at the address specified. In this case, that would happen
to be $AR at address $DB3C and $^fi at address $0330. It would then
help you by printing part of the next expected instruction. The computer
expects that you will type a line starting with
A naaE
It places the first part of this line on the screen to save you typing. The
screen should now look like this:
A 0330 LDft #$A&
ft □33E
You may now complete the instruction by typing in JSR $FFDE and
pressing RETURN. Again, the computer will anticipate your next line by
printing ft 0341, which allows you to type in the final command, BRK.
The screen now looks like this:
ft 033C LDft #$4fl
ft □33E JSR $FFD5
ft □3^1 BRK
ft □3/;2
The computer is still waiting for another instruction. We have no more
instructions, so we press RETURN to signal that we're finished.
At this point, our program is stored in memory. The instructions have been
assembled directly into place, and the object code is hopefully ready to
go.
Note that this saves us the trouble of remembering— or looking up— the
op codes for each instruction. And we don't need to keep track of how
long each instruction should be; the assembler does it for us.
CONTROLLING OUTPUT
29
If you like, you can display memory and look at the object program with
theM 0330 □3^1. You'll see the bytes of your program in memory:
. :D33C ftq 4fl 50 D5 FF □□ xx xx
The first six bytes are your program. The last two bytes don't matter: they
were whatever was in that part of memory before. We don't care what is
there, since the program will stop when it reaches the BBK ($□□) at
address $ □ 3 < 1 ; it won't be concerned with the contents of memory at
$D34E or $03^3.
Checking: The Disassembler
When we changed our source code into object code, we called this process
of translation assembly, and we called a program that did the job an
assembler.
Now we've written a program and it's safely stored in memory. We have
inspected memory and have seen the bytes there; but they are hard to
read. It would be convenient if we could perform an inverse assembly,
that is, take the contents of memory and translate it into source code. The
monitor has this capability, called a disassembler.
If we ask the computer to disassemble the code starting at $D33C, it will
examine the code there and establish that the contents ($ AR) correspond
to an LDR immediate command. It will then print for our information LDA
#$4 fl, which is much more readable than the original two bytes, ftR A&.
Give the command D 033C and press RETURN. D stands for disas-
semble, of course, and the address must follow.
The computer will now show a full screen of code. On the left is the address
followed by the bytes making up the instruction. On the right is the re-
constructed source code. The screen shows much more memory than our
program needs. Again, we ignore all lines beyond address $Q3A1, which
is the last instruction of our program. Anything following is "junk" left in
memory that the program does not use.
An interesting feature of most disassembly listings is that the cursor is left
flashing on the last line of the disassembly rather than on the line below.
When you have a large program, this allows you to type the letter D
followed by RETURN and the next part of your program will immediately
be displayed. On the other hand, if you don't want to disassemble more
code, press the cursor down key and move to a "clean" line before typing
your next instruction.
30
MACHINE LANGUAGE FOR COMMODORE MACHINES
A disassembly is a good way to check for errors. If you find an error in
tiie listing, you may correct that line by re-assembling it, using the ft
command once again. Minor errors may be corrected directly on the left-
hand side of the disassembly listing. In other words, suppose that you had
incorrectly coded LDft #$5fl during the assembly phase; when you per-
form the disassembly, this line will show as
. / Q33C ftq 5fl LDfi #$5a
You recognize that the 56 should be A&; you may move the cursor up—
use cursor home if you wish — and type over the value on the left-hand
side. In this case, you place the cursor over the 5, type A to change the
display to < fl, and press RETURN. You will see from the display that the
problem has been fixed.
If necessary, move the cursor down to an empty line. Type the command
G 03 3 C and the program will run. Again, it doesn't take long; the break
back to the MLM seems instantaneous. Where's the letter H that we were
supposed to print? It's hard to see, but it's there. Look at your G 0330
command and you'll see it.
Project for enthusiasts: Can you add to the program and print HI? The
ASCII code for the letter I is $A'=\. Can you add again and print HI on
a separate line? The ASCII code for a RETURN is $DD. Remember that
you can find all ASCII codes in Appendix D; look in the column marked
ASCII.
So far we have started up our programs with a G (go) command from
the MLM, and we have terminated our programs with a BRK command
that returns us to the monitor. That's not a convenient way to run a program;
most users would prefer to say RUN out of BASIC and have the computer
do everything.
We can link to a machine language program from BASIC and when the
program is finished, it can return to BASIC and allow the BASIC program
to continue to run. The commands we need are
(BASIC) SYS— Go to a machine language subroutine at the stated address;
(Machine language) ETS— Return to whoever called this subroutine.
Running the Program
BASIC
CONTROLLING OUTPUT
31
Let's change our machine language program first. We must change the
BEK at the end to RTS (return from subroutine) so that when the program
is finished it will return to BASIC. If you like, you may change it directly
on the disassembly listing: disassemble and then type over the □□ byte
that represents BEK with a value of bO. Press RETDRN and you'll see
that the instruction has now changed to RTS. Alternatively, you may re-
assemble with
a 033CLDA#$4fl
a 033E JSR $FFD5
ft U3A1 RTS
Now return to BASIC (using the X command). The computer will say
REftDY; you may now call your program with a SYS command.
Address $D33CisflEflin decimal. Thus, we type SYS flEfl.Whenwe
press RETURN, the tetter H will be printed.
We're not finished. Any machine language subroutine may be called from
a BASIC program. Type NEW, which clears out the BASIC work area; our
machine language program is left untouched, since NEW is a BASIC com-
mand. Now enter the following program:
FOR J = 1T0 1D
IID SYS flEfl
15D NEXT J
How many times will our program atflEfl($D33C)be called? How many
times will the letter H be printed? Will they be on the same line or separate
lines? Type RON and see.
Project for enthusiasts: Again, change the machine language program
to say HI. Use your imagination. What else would you like the computer
to say? Would you like to use colors or reverse font?
We've achieved an important new plateau: BASIC and machine language
working together. It's easier on the user, who doesn't have to learn spe-
cialized monitor commands. It's easier on the programmer, too, since
things that are easy to do in BASIC can be written in that language; things
that are clumsy or slow in BASIC can be written in machine language. We
can get the best of both worlds.
Let's distinguish our three different types of subroutine calls:
GOSDB— calls a BASIC subroutine from a BASIC program.
SYS — calls a machine language subroutine from a BASIC program.
JSR— calls a machine language subroutine from machine language.
32
MACHINE LANGUAGE FOR COMMODORE MACHINES
Loops
We know how to send characters to the screen, one at a time. But long
messages, such as THE QUICK BROWN CRT . . ., might lead to te-
dious coding if we had to write an instruction for each letter to be sent.
We need to set up a program loop to repeat the printing activity.
Let's write a program to print the word HELLO followed by a RETURN.
C128 note: Remember to check Exercises for the Commodore 128, in
Appendix E, for the appropriate coding.
We must store the word HELLO somewhere in memory. It doesn't matter
where, provided it doesn't conflict with anything else. I'll arbitrarily choose
address $034Ato $Q3AT. We'll put it there in a moment. Remember
that the characters that make up the word HELLO (plus the RETURN)
are not program instructions; they are simple data. We must put them in
place with a memory change — we must not try to assemble them.
We will need to count the characters as we send them. We wish to send
six characters, so a count of six is our limit. Let's use the X register to
keep track of the count. First, we must set X to zero:
a a33C LDX #$0D
Note that we use the # symbol to denote an immediate value: we want
to load X with the value zero, not something from address □. Now, we'll
do something new. I want to take a character to be printed from address
$D3<A. But wait, that's only the first time around. When we come back
to this point in the loop, I want to take a character from $ □ 3 4 B , and then
from $Q3AC, and so on.
How can we do this? It seems that we must write one address into the
LDA instruction, and that address can't change. But there is a way.
We can ask the computer to take the address we supply, and add the
contents of X or Y to this address before we use it. The computed address
is called an effective address.
Let's look at our position. The first time around the loop, X is counting the
characters and has a value of zero. If we specify our address as □ 3 ft + X ,
the effective address will be 034 ft. That's where we will have stored the
letter H.
When we come back around the loop — we haven't written that part yet —
X should now equal one. An address of □ 3 4 ft + X would give an effective
address of 034 B; the computer would go there and get the letter E. As
CONTROLLING OUTPUT
33
we go around the loop, the letters, L, L, 0, and RETURN will be brought
In as needed.
As we enter the LD A instruction, we don't type the plus sign. Instead, we
signal indexing with a comma: LDa$D3<ft,X.We may use either X or
Y for indexing: they are sometimes called index registers. In this case, of
course, we use X. So we code
A n33E LDA$034A,X
A 03^1 JSR $FFD5
The first time, the computer loads the contents of address $03 A k (the
letter H of HELLO) and prints it. When the loop comes back here, with
X equal to one, this instruction will load the contents of $ 03^6 and print
the letter E.
The X register counts the number of letters printed, so we must add one
to the contents of X. There's a special command that will add one to the
contents of X: I NX, for increment X. A similar code, I NY, allows Y to
be Incremented; and DEX (decrement X) and DEY (decrement Y) allow
X or Y to be decremented, or reduced, by one. At the moment, I NX is
the one we need for counting:
A Q3AA INX
Now we can test X to see if it is equal to six yet. The first time around, it
won't be since X started at zero and was incremented to a value of 1. If
X is not equal to six, we'll go back to $D33E and print another letter.
Here's how we code it:
A DS^B CPX#$Dt
A 0347 BNE $D33E
CPX stands for compare X; note that we are testing for an immediate
value of six, so we use the # symbol. BNE means branch not equal; if X
is not equal to six, back we go to address $D33E.
A little careful thought will reveal that the program will go back five times
for a total of six times around the loop. It's exactly what we want.
Let's show the whole code, completing it with RTS:
A 033C LDX#$QD
A 033E LDA$D3<A,X
A 03^1 JSR $FFD2
A Q3AA INX
AD3AS CPX#$Qt
A n3A7 BNE $D33E
A Q3A^ RTS
34
MACHINE LANGUAGE FOR COMMODORE MACHINES
We may now put the characters for HELLO into memory. These are data,
not instructions, so we must not try to assemble them. Instead, we change
memory in the usual way, by displaying and then typing over. We give
the command M D3<A D3^F, and type over the display to show
:D3<a A& AS AC AC UJ) XX XX
By a lucky coincidence, this data fits exactly behind our program.
Everything should be ready now. Disassemble the program at $D33C
and check it. You may note that the data at $ □34ft doesn't disassemble
too well, but that's to be expected; these bytes are not instructions and
cannot be decoded.
When all looks well, return to BASIC (with .X) and try SYS flSfl. The
computer should say HELLO.
Once again, set up a BASIC loop program:
!□□ FOR J = 1T0 3
110 SYS as a
IBD NEXT J
A Comment on SAVE
If you wished to save the program to cassette tape, you'd have a problem
on the VIC or Commodore 64. The machine language program is in the
cassette buffer; a save-to-tape command would cause the contents of that
buffer to be destroyed before the program could be written to tape. Even
disk commands would not be completely safe: 4.0 BASIC disk commands
use the cassette buffer area as a work area; using these commands would
probably destroy our machine language program.
But saving the program is not the main problem. A correctly saved program
can give trouble when you try to bring it back and run it safely. The difficulty
is related to BASIC pointers, especially the start-of-variables pointer. The
problem, and how to solve it, will be discussed in some detail in Chapter
6.
A Stopgap SAVE
We can presen/e short programs by making them part of DfiTft state-
ments. The procedure is not difficult if screen editing is used intelligently.
We note that the program extends from $D33Cto$D3<F, including the
message (HELLO) at the end. The decimal equivalents to these ad-
dresses are a 5 a to a < 7 . C1 28 note: Appendix E, in the section Exercises
CONTROLLING OUTPUT
35
for the Commodore 128, will give you the correct addresses and values
for doing this on the C128. Enter the following BASIC line:
FOR J = flea TO fl-^? : PRINT PEEK (J) ; :NEXT J
Study the above line. You will see that it asks BASIC to go through the
part of memory containing your machine language program, and display
the contents (in decimal notation, of course). You'll see a result that looks
something like this:
ite D laq 3 510 555 533 5E/; y eoa sas qt
75 7t> 7b m 13
These are indeed the bytes that make up your program. With a little study,
you could reconstruct the It5-D combination to be LDX #$□□, or the
7 E-t R-7 1-7 1-7 q at the end to be the word HELLO in ASCII. It looks
different when it's in decimal, but it's still the same numbers.
You may try a little skill and artistry, using screen editing to perform the
next activity, or you may just retype the numbers into data lines a shown.
Either way, arrange the numbers as follows:
50 DATA lt5,D,lflS,74,3,35,21D,255,E32,5S<,t
tD DATA EDfl/E<5,qt,72,tH,7t,7t,7R,13
We now have a copy of our program, exactly the way it appears in memory,
but stored within DATA statements. The DATA statements are part of a
normal BASIC program, of course, and will SAVE and LOAD with no
trouble at all.
We can now reconstruct our machine language program, placing it back
into memory, with a simple BASIC POKE program:
an FOR j = flEa TO a^7 : read x:poke J, X: next J
Now our program is safe and sound — it handles like BASIC, but it will do
a machine language task for us as desired. Let's display the entire BASIC
program
50 DATA lt.3, 0,169, 7^,3, 35, 210,555, 232, S5<,t
to DATA 50fl,5^5,Rt.,75,tq,?t.,?t,7q,13
flO FOR J=fl5fl TO fl'!;7 : READ X: POKE J,X:NEXT J
100 FOR J= 1 TO 3
110 SYS 350
150 NEXT J
This method of saving a machine language program is clean and trouble
free, but it becomes awkward where long programs are involved. More
advanced methods will be discussed in Chapter 6.
36
MACHINE LANGUAGE FOR COMMODORE MACHINES
Things You Have Learned
—Subroutines can be called from machine language using the JSR command.
There are several useful kernal subroutines permanently available.
—A BASIC program may call a machine language program as a subroutine:
the BASIC command is SYS. The machine language subroutine returns to
the calling point with an RTS (return from subroutine) instruction.
—The CHROUT subroutine at address $FFDE allows output of a character,
usually to the screen. In addition to printable characters, special cursor- and
color-control characters may be sent.
— Most machine language monitors have a small assembler to help program
preparation, and a disassembler to assist in program checking.
—Immediate mode Is signaled by use of the # symbol. The computer Is asked
to take the value given, instead of going to a specified address for its data.
—X and Y are called index registers. We may add the contents of X or Y to a
specified address, to create an effective address that changes as the program
runs. This addition Is called indexing.
— X and Y also have special instructions that increase or decrease the selected
register by one. These are called increment and decrement instructions, and
are coded INX, INY, DEX, and DEY.
Questions and Projects
Look through the table of ASCII characters in Appendix D. Note that hex
13 Is "clear screen." Write a program to clear the screen and print "HO
HO! ".
You may have noticed that in our example, we had register X counting
up from zero to the desired value. What would happen if you started X at
5 and counted down? Try it if you like.
Remember that you can also include cursor movements, color codes (if
your machine has color), and other special ASCII characters. Could you
lay out the coding to draw a box? (Try it in BASIC first). Draw a box with
the word HELLO inside it.
3
Flags, Logic,
and Input
This chapter discusses:
• Flags that hold status information
• Testable flags: Z, C, N, and V
• Signed numbers
• The status register
• First concepts of interrupt
• Logical operators: OR, RND, EOR
• The GE TIN subroutine for input
• The STOP subroutine
39
40
MACHINE LANGUAGE FOR COMMODORE MACHINES
Flags
Near the end of Chapter 2, we coded a program that had the seemingly
natural sequence
CPX #$0t
BNE $ . . . .
It made sense: compare X for a value of t, and if not equal, branch back.
Yet it implies something extraordinary; the two instructions are somehow
linked.
Let's flash fonward for a moment. Even when you have a machine language
program running, the computer "freezes" sixty times a second. The com-
puter undertakes a special activity, called interrupt processmg. It stops
whatever it was doing, and switches to a new set of programs that do
several tasks: flashing the cursor, checking the keyboard, keeping the
clock up to date, and checking to see whether the cassette motor needs
power. When it's finished, it "unfreezes" the main program and lets it
continue where it left off.
This interrupt might take place between the two instructions shown above,
that is, after the CPX and before the BNE. Hundreds of interrupt instruc-
tions might be executed between the two, yet nothing is harmed. The two
instructions work together perfectly to achieve the desired effect. How can
the compiL|ter do this?
The two instructions are linked by means of a flag— a part of the 650x
that records that something has happened. The CPX instruction tests X
and turns a special flag on or off to signal how the comparison turned out:
equal or unequal. The BNE instruction tests that flag. If it's on (meaning
equal), no branch will take place and the program will continue with the
next instruction; if it's off (meaning not equal), a branch will take place.
In other words, some instructions leave a "trail" of status information; other
instructions can check this information. The status information is called
"flags." There are four flags that may be tested: Z, C, N, and V. They are
discussed below.
Z Flag
The Z (zero) flag is probably misnamed, and should have been called the
E flag (for "equals"). After any comparison (CPX to compare X, CPY to
compare Y, or CMP to compare R), the Z flag will be set to "on" if the
compared values are equal; othenwise it will be reset to "off."
FLAGS. LOGIC. AND INPUT
41
Sometimes the Z flag checks for equal to zero, hence its name, Z for
zero. This happens for every activity that may change one of the three
data registers. Thus, any load command will affect the Z flag status. The
same is true of increment and decrement instructions, which obviously
change registers. And later, when we meet other operations such as ad-
dition and subtraction, they too will affect the Z flag.
There are many instructions that don't affect the Z flag (or any flag, for
that matter). Store instructions (STR, STX, STY), never change a flag.
Branch instructions test flags but don't change them.
An example will help illustrate the way that some instructions change flags
and others do not. Examine the following coding:
LDA #$53 (Load 53 to A)
LDX #$□□ (Load zero to X)
STa$153< (store 53 to address $1534)
BEQ$
Will the branch (BEQ) be taken, or will the 650x continue with the next
instruction? Let's analyze the Z flag's activity step by step. The first in-
struction (LDA #$53) resets the Z flag, since 53 is not equal to zero.
The second instruction (LDX #$□□) sets the Z flag because of the zero
value. The third instruction (STA $1534) does not affect the Z flag; in
fact, store instructions do not affect any flags. Thus, by the time we reach
the BEQ instruction, the Z flag is set "on" and the branch will be taken.
650x reference manuals show the specific flags that are affected by each
instruction. In case of doubt, they are easy to check.
The Z flag is quite busy — it clicks on and off very often since many in-
structions affect it. It's an important flag.
If the Z flag is set "on," the BEQ (branch equals) instruction will branch
to the specified address; othenwise it will be ignored and the next instruction
in sequence will be executed. If the Z flag is reset "off," the BNE (branch
not equals) instruction will branch.
We can see in more detail how our program from Chapter 2 worked.
CPX #$Dt causes the Z flag to be set "on" if X contains the value t;
othenwise it causes the Z flag to be reset "off." BNE tests this flag, and
branches back to the loop only if the Z flag is off — in other words, only If
the contents of X is not equal to six.
42
MACHINE LANGUAGE FOR COMMODORE' MACHINES
C Flag
The C (carry) flag is probably misnamed, too. It should have been called
the GE (greater/equal) flag, since after a comparison (CP X, CP Y, or CMP),
the C flag is set "on" if the register (X, Y, or A) is greater than or equal
to the value compared. If the register concerned is smaller, the C flag will
be reset "off."
The C flag is not as busy as the Z flag. The C flag is affected only by
comparison instructions and by arithmetic activities (add, subtract, and a
type of multiplication and division called rotate or shift). When used in
arithmetic, the C flag is properly named, since it acts as a "carry" bit
between various columns as they are calculated. For example, an LDR
instruction always affects the Z flag since a register is being changed, but
never affects the C flag since no arithmetic or comparison is being per-
formed.
If the C flag is set "on," the BCS (branch carry set) instruction will branch
to the specified address; otherwise it will be ignored and the next instruction
in sequence will be executed. If the C flag is reset "off," the BCC (branch
carry clear) instruction will branch.
The C flag may be directly set or reset by means of the instructions SEC
(set carry) and CLC (clear carry). We will use these instructions when we
begin to deal with addition and subtraction.
If you examine the last program of Chapter 2, you will see that the BNE
instruction could be replaced by BCC. Instead of "branch back if not equal
to 6," we could code "branch bacl< if less than 6." The operation would
be the same in either case.
N Flag
The N (negative) flag is also probably misnamed. It should have been
called the HB (high bit) flag, since numbers are positive or negative only
if they are used in a certain way. The N flag is set to indicate that a register
has been given a value whose high bit is set.
The N flag is as busy as the Z flag; it changes with every instruction that
affects a register. The N flag is affected by comparisons, but in this case
its condition is not usually meaningful to the programmer.
To sort out the operation of the N flag, it's important to become familiar
with hexadecimal-to-binary conversion. For example, will LDR #$b5 set
the N flag? Rewrite it into binary: $ 1 5 equals ^ □ 1 1 □ □ 1 □ 1 . We can see
FLAGS, LOGIC, AND INPUT
43
that the high bit is not set, meaning that the N flag will be off after loading
this value. As another example, suppose we LDX #$Da. Hex Dfi is
IIDIIDID binary. We see that the high bit is on and thus the N flag is
set.
If the N flag is set "on," the BMI (branch minus) instruction will branch
to the specified address; othenwise it will be ignored and the next instruction
in sequence will be executed, if the N flag is reset "off," the BPL (branch
plus) instruction will branch.
A Brief Diversion: Signed Numbers
How can a location— which is usually thought to contain a decimal value
from □ to E55 — contain a negative number? It's up to the programmer
to decide whether a memory value is unsigned, having a value range from
to 555, or signed, having a value range from -15flto+127. There
are still a total of E5t possibilities. The computer's memory simply holds
bits, while the programmer decides how the bits are to be used in a specific
case.
IVIathematically, it's described this way: signed numbers, if desired, are
held in two's-complement form. We can hold - 1 as hex FF, and - 2
as hex FE, all the way down to - 1 2 fl as hex fl 0. You may have noticed
that in all the examples, the high bit is set for these negative numbers.
We may need more intuitive help, however. If the computer loads the
decimal value 2DD into the A register with LDA #$Cfl, the N flag will be
set and will seemingly indicate that E D □ is a negative number. It may be
more comfortable to simply thini< of SDD as a number with the high bit
set. But in a sense, EDO could be a negative number if we wanted it to
be. Let's examine the situation by means of examples.
If I were asl<ed to count down in hexadecimal from !□, I'd start out $!□,
$DF,$DE,and$DD, continuing down to $ □ E , $ □ 1 , and $ □ □ . If I needed
to keep going, I'd continue past $00 with $FF; in this case, hex FF would
clearly represent negative one. Continuing, FE, FD, and FC would rep-
resent -E, -3, and - A. And the high bit is set on all these "negative"
numbers.
Let's discuss a decimal analogy. Suppose you have a cassette recorder
with a counter device attached, and the counter reads 0025. If you rewind
the unit a distance of 30 units, you would not be surprised to see a value
of 9995 on the counter and would understand that it meant a position of
-5. If you had a car with 1 ,500 miles on the odometer, and "rolled back"
44
MACHINE LANGUAGE FOR COMMODORE MACHINES
the mileage by 1 ,501 miles, you'd see a reading of 99999, whicli would
mean - 1 . (The author does not know this from personal experience, but
is assured by many machine language students that it is so.) In these
cases, based on the decimal system, the negative numbers are called
"ten's complement."
V Flag
As with the other flags, the V (overflow) flag is probably misnamed. It
should have been called the SAO (signed arithmetic overflow) flag, since
it is affected only by addition and subtraction commands, and is meaningful
only if the numbers concerned are considered to be signed.
The V flag is used only occasionally in typical 650x coding. Many machine
language programs don't use signed numbers at all. The most typical use
of the V flag is in conjunction with a rather specialized command, BIT
(bit test). For this instruction, the V flag signals the condition of bit t of
the memory location being tested. In this case, V and N work in a similar
way: N reflects the high bit, bit 7, and V represents the "next bit down,"
bit b. The BIT command is used primarily for testing input/output ports
on I A (interface adaptor) chips.
If the V flag is set "on," the BVS (branch overflow set) instruction will
branch to the specified address; otherwise it will be ignored and the next
instruction in sequence will be executed. If the V flag is reset "off," the
BVC (branch overflow clear) instruction will branch.
The V flag may be directly reset by means of the CLV (clear overflow)
instruction. Oddly, there is no equivalent instruction to set the flag.
One special feature of the V flag: on some 650x chips, the V flag can be
set by hardware. There is a pin on the chip that can be used so that an
external logic signal will trigger the V flag.
A Brief Diversion: Overflow
The term overflow means "the result is too big to fit." For example, if I
add eOD to EDO, the total is ^^DO ... but this won't fit in a single byte.
If we have only a single byte to store the result, we say that the addition
has encountered overflow, and we can't produce a meaningful answer.
If we are using unsigned numbers, the C flag tells us about overflow. If
we are using signed numbers, V tells the story. We'll take this up again
in the next chapter.
FLAGS, LOGIC, AND INPUT
45
Flag Summary
A brief table may help review the four testable flags.
Flag Brief Activity
Name Meaning Level
Branch Taken If:
Set Not-Set
Z Zero, equal Busy
C Carry, greater/equal Quiet
N Negative, high-bit Busy
V Signed arithmetic overflow Quiet
BEQ BNE
ECS BCC
BMI BPL
BVS BVC
The Status Register
The preceding flags— and three others— may be viewed within the status
register (SE). You may recall that the machine language monitor gives
an SR display. If you know how to read it, you can see the condition of
all flags.
Each flag is a bit within the status register. Again, it's useful to be able to
easily translate the hexadecimal display, so as to view the individual flags.
Here's a chart of the flags within the status register:
NV-BDIZC
Taking the bits one at a time, starting at the high bit:
N— the N flag, as above
V — the V flag, as above.
Bit 5— unused. You'll often find that this bit is "on."
B— "Break" indicator. When an interrupt occurs, this signals whether or not the
interrupt was caused by a BRK instruction.
D— Decimal mode indicator. This changes the manner in which the add and
subtract instructions operate. In Commodore machines, this flag will always be
off. Don't turn it on unless you know exactly what you're doing. This flag may
be turned on with the SED (set decimal) instruction, and turned off with the
OLD (clear decimal) instruction.
I— Interrupt disable. More exactly, this bit disables the IRQ (interrupt request)
pin activity. More on this control bit much later. This flag may be turned on with
the SEI (set interrupt disable) instruction, and turned off with the CLI (clear
interrupt disable) instruction.
Z — the Z flag, as above.
C — the C flag, as above.
46
MACHINE LANGUAGE FOR COMMODORE MACHINES
Flags B, D, and I are not testable flags in that there are no branch instructions
that test them directly. D, the decimal mode flag, and I, the interrupt locl<out
flag, may be considered "control" flags. Instead of reporting conditions found
as the program runs, they control how the program operates.
When we see a value displayed in the SR, or status register, we may
examine it to determine the condition of the flags, especially the testable
flags Z, C, N, and V. For example, if we see an SR value of $B1, we
translate to binary ^IDllODDl and know that the N flag is on, the V
flag is off, the Z flag is off, and the C flag is on.
You may change these flags by typing over the displayed value in the
machine language monitor. Be careful you don't accidentally set the D or
I flags.
A Note on Comparison
If we wish to compare two bytes with each other, we must perform a
comparison. One value must be in a register (ft, X, or Y); the other must
either be stored in memory, or must be an immediate value we use in the
instruction.
We will use the appropriate compare instruction depending on the register
involved; CMP for the ft register, CPX for the X register, and CPY for the
Y register. Following the comparison, we may use any of the following
branch tests:
BE Q— branches if the two bytes are equal.
BNE— branches if the two bytes are not equal.
BCS— branches if the value in the register is greater than or equal to the other
value.
BCC — branches if the vaiue in the register is iess than the other value.
We can use more than one branch instruction after a comparison. Suppose
our program wanted to test the Y register for a value equal to or less than
5. We might code
CPY #$05
BEQ - . somewhere
BCC . . somewhere
We can see that our code will branch if the value is equal to 5 (using the
BEQ) or less than 5 (using the BCC); othenwise it will continue without
branching. In this case, we could make the coding more efficient by chang-
ing it to read
FLAGS, LOGIC, AND INPUT
47
CPY #$Dt
BCC . . somewhere
A little common sense will tell us that testing a number to see if it is less
than h is the same as testing it to see if it is less than or equal to S.
Common sense is a valuable programming tool.
We have looked at the three data registers — ft, X, and Y — and have seen
three types of operation we can perform with them:
Compare: CMP, CPX, CPY
Up to this point, the registers have identical functions, and we can use
any of them for any of these functions. But new instructions are creeping
in that give a different personality to each of the three.
We have noted that INX, INY, DEX, and DEY for increment and dec-
rement are restricted to X and Y only; and we've also mentioned that X
and Y can be used for indexing. Soon, we'll start to examine some of the
functions of the A register, which is often called the accumulator because
of its ability to do arithmetic.
We have seen JSR, which allows us to call a subroutine of prewritten
instructions. We've used RTS, which says, "Go back to the calling point,"
even if the calling point is a BASIC program. And we've almost abandoned
the BRK instruction, which stops the program and goes to the machine
language monitor. BRK will be useful in checking out programs. Specifi-
cally, we can stop a program at any time by inserting a BRK instruction,
allowing us to see whether the program is behaving correctly and whether
it has dorle the things we planned.
There are eight branch instructions. They have already been discussed,
but there is one additional piece of information that is important to keep
in mind. All branches are good only for short hops of up to a hundred
memory locations or so. So long as we write short programs, that won't
be a limitation; but we'll look at this more closely in Chapter 5.
Three instructions perform what are called logical operations. They are:
AND (Logical AND); ORA (Logical OR); and EOR (Exclusive OR). These
instructions work on the A register only.
Instructions: A Review
Load:
Store:
LDA, LDX, LDY
STA, SIX, STY
Logical Operators
48
MACHINE LANGUAGE FOR COMMODORE MACHINES
Mathematicians describe these operations as commutative. For example,
a value of $3ft "AND" $57 gives exactly the same result as $57
"AND" $3 A. The order doesn't matter. But we often use these func-
tions — and thinl< of them — in a particular order. It's the same as with
addition, where we think of a "total" to which is added an "amount" to
make a "new total." With the logical operators we often think of a "value,"
which we manipulate with a "mask" to make a "modified value."
Logical operators work in such a way that each bit within a byte is treated
independently of all the other bits. This makes these instructions ideal for
extracting bits, or manipulating certain bits while leaving others alone.
We'll look at formal definitions, but the following intuitive concepts are
useful to programmers:
AND — turns bits off.
OEA — turns bits on.
EOR — flips bits over.
AUD— Logical AND to A
For each bit in the A register, AND performs the following action:
Original A Bit Mas/f Resuiting A Bit
□
1 □ □
□ 1 □
1 1 1
Examine the upper half of this table. When the mask is zero, the original
bit in A is changed to zero. Examine the lower half. When the mask is
one, the original bit is left unchanged. Hence, AND can selectively turn
bits off.
Example: Turn off bits A, 5, and t in the following value: $C7
Original value: llODOlll
Mask: AND IDDailll (hex flF)
Result IDDDDlll
XXX
Note that the bits marked have been forced to "off," while all other bits
remain unchanged.
FLAGS, LOGIC, AND INPUT 49
OR A— Logical OR to A
For each bit in the ft register, OR ft performs the following action:
Original A Bit Mas/c Resulting fl Bit
□ □ □
1 □ 1
□ 1 1
111
Examine the upper half of this table. When the mask is zero, the original
bit in A is left unchanged. Examine the lower half. When the mask is one,
the original bit is forced to "on." Hence, OR ft can selectively turn bits on.
Example: Turn on bits A, S, and t in the following value: $C7
Original value: llDDDlll
Mask: ORA DlliaaDD (hex ?□)
Result 11110111
XXX
Note that the bits marked have been forced to "on," while all other bits
remain unchanged.
EOR— Exclusive OR to A
For each bit in the A register, EOB performs the following action:
Original A Bit Mask Resulting A Bit
□ □ □
10 1
Oil
110
Examine the upper half of this table. When the mask is zero, the original
bit in A is left unchanged. Examine the lower half. When the mask Is one,
the original bit is inverted; zero becomes one and one becomes zero.
Hence, EOR can selectively flip bits over.
Example: Invert bits A, 5, and t in the following value: $C7
Original value: 11000111
Mask: EOR 01110000 ( hex 70 )
Result
lOllDlll
50
MACHINE LANGUAGE FOR COMMODORE MACHINES
Note that the bits marked have been flipped to the opposite value, while
all other bits remain unchanged.
Why Logical Operations?
We use these three commands— ft ND, ORft, and EOR— to change or
control individual bits within a byte of information. The commands are
unusual in that each bit may be manipulated independently of the others.
We don't seem to be working with numbers when we use these commands.
Rather, we're working with each individual bit, turning it on or off as we
wish.
Why would we turn individual bits on or off? There are several possible
reasons. For example, we might wish to control external devices through
the Ift's (interface adaptors). Within the Ift's input and output ports each
of the eight bits might control a different signal; we might want to switch
one control line on or off without affecting other lines.
When we're looking at input from an I ft port, we often read several input
lines mixed together within a byte. If we want to test a specific bit to see
if it is on or off, we might mask out all other bits with the ftND instruction
(changing unwanted bits to zero); if the remaining bit is zero, the whole
byte will now be zero and the Z flag will be set.
Why would we want to flip bits over? Many "oscillating" effects— screen
flashing or musical notes— can be accomplished this way.
Finally, the logical operators can be useful in code translation. For ex-
ample, here are the values for ASCII 5 and binary 5:
ASCII fOOllDlDl
Binary ^OODODlOl
We must use the ASCII value for input or output. We must use the binary
value for arithmetic, particularly addition and subtraction. How could we
get from one to the other? By taking bits out (RND) or putting bits in (ORR).
Alternatively, we could use addition or subtraction; the logical operators,
however, are simplier.
Input: The GE T I N Subroutine
We have seen how we can use CHROUT at $FFD2 to produce output
to the screen. Now we'll look at the input side— how to use the GETIN
subroutine at $FFE4 to get characters from the keyboard buffer.
FLAGS, LOGIC, AND INPUT
51
You may be familiar witli tlie GET statement in BASIC. If so, you'll find
the same characteristics in GETIN:
• Input is taken from the keyboard buffer, not the screen.
• If a key Is held down, it will still be detected once only.
• The subroutine returns immediately.
• If no key is found, a binary zero is returned in A.
• If a key is found, its ASCII value will be in A.
• Special keys, such as RETURN, RVS, or color codes, will be detected.
To call for a key from the keyboard, code JSR $FFE4. Values in X and
Y are not guaranteed to be preserved, so if you have important information
in either register, put it away into memory.
Subroutine: GETIN
Address: SFFE-^
Action: Takes a character from the input channel and places it
into the A register. The input channel is the keyboard input
buffer unless arrangements have been made to switch it.
The character received is usually ASCII (or PET ASCII). When read
from the keyboard, the action is similar to a BASIC GET statement:
one character will be taken from the buffer; it will not be shown on the
screen. If no character is available from the keyboard input buffer, a
value of binary zero will be put into the A register. The subroutine will
not wait for a key to be pressed but will always return immediately.
Registers: The A register will of course always be affected. X and Y
are likely to be changed; do not have data in these when calling
GETIN.
Status: Status flags may be changed. In most recent Commodore
machines, the C (carry) flag indicates some type of problem with input.
If we want keyboard input to appear on the screen, we should follow a
call to GETIN, $FFE4, with a call to CHRODT, $FFD2, so that the
received character is printed.
STOP
Machine language programs will ignore the RUN/STOP key . . . unless
the program checks this key itself. It may do so with a call to STOP,
address $FFE1. This checks the RUN/STOP key at that moment. To
make the key operational, $FFE1 must be called frequently.
52
MACHINE LANGUAGE FOR COMMODORE MACHINES
A call to FFEl should be followed by a BEQ to a program exit so that
the program will terminate when RUN/STOP Is pressed.
The RON/STOP key is often brought Into play while programs are being
tested, so that unexpected "hangups" can still allow the program to be
terminated. Coding to test the RUN/STOP key is often removed once
testing is complete, on the assumption that no one will want to stop a
perfect program. Incidentally, if you plan to write nothing but 100 percent
perfect programs, you will not need to use this subroutine.
Subroutine: STOP
Address $FFE1
Action: Check the EUN/STOP key. If RDN/STOP is being pressed
at that instant, the Z flag will be set when the subroutine
returns.
In PET/CBM, the system will exit to BASIC and say READY if the
RUN/STOP key is being pressed. In this case, it will not return to the
calling machine language program.
Registers: A will be affected. X will be affected only if the RUN/STOP
key is being pressed.
Status: Z signals whether RUN/STOP is being pressed.
Programming Project
Here's our task: we wish to write a subroutine that will wait for a numeric
key to be pressed. All other keys (except RUN/STOP) will be Ignored.
C128 note: Remember to check Appendix E, under Exercises for the
Commodore 128, for the appropriate coding.
When a numeric key is pressed, it will be echoed to the screen, and then
the subroutine will be finished. One more thing. The numeric character
will arrive in ASCII from the keyboard: we wish to change It to a binary
value before giving the final RTS statement. This last operation has no
useful purpose yet, except as an exercise, but we'll connect it up in the
next chapter.
Coding sheets ready? Here we go.
A 0330 JSR $FFE1
We will check the RUN/STOP key first. But wait. Where will we go if we
find that the key is pressed? To the RTS, of course; but we don't know
FLAGS, LOGIC, AND INPUT
53
where that is, yet. In these circumstances, we usually make a rough guess
and correct it later. Make a note to check this one . . .
A 0337 BEQ $0351
a D3A1 JSR $FFE4
Now we've gotten a character; we must check that it's a legitimate numeric.
The ASCII number set to "=1 has hexadecimal values $3 □ to $31. So
if the value is less than $3 0, it's not a number. How do we say "less
than?" After a compare, it's BCC (branch carry clear). So we code
A U3AA CMP #$3D
a 034t. BCC $D33C
Did you spot the use of immediate mode at address $U3AA7 Make sure
you follow the logic on this. Another point: what if no key has been pressed?
We're safe. There will be a zero in the a register, which is less than hex
3D; this will cause us to go back and try again.
Now for the high side. If the number is greater than hex 3R, we must
reject it since it cannot be an ASCII numeric. Our first instinct is to code
CMP #$39 and BCS. But wait! BCS (branch carry set) means "branch
if greater than or equal to." Our proposed coding would reject the digit =1,
since the carry flag would be set when we compared to a value of hex
3q.
We must check against a value that is one higher that $3R. Be careful,
though, for we're in hexadecimal. The next value is $3 a. Code it:
a Q3A& CMP #$3a
a □3<a BCS $D33C
If we get this far, we must have an ASCII character from □ to 'I ; let's print
it to the screen so that the user gets visual feedback that the right key
has been pressed:
a D3AC JSR $FFDE
Now for our final task. We are asked to change the ASCII character into
true binary. We may do this by knocking off the high bits. We remember,
of course, that to turn bits off we must use aND:
a D3AF aND #$DF
a 0351 RTS
It's a good thing that we printed the character first, and then converted to
binary; the character must be ASCII to print correctly.
54
MACHINE LANGUAGE FOR COMMODORE MACHINES
One last thing. We had a branch (on the RUN/STOP key) that needed to
connect up with the RTS. Did you mal<e that note about going bacl< and
fixing up the branch? Now is the time to do it, but before you go bacl<,
terminate the assembly with an extra RETURN on the keyboard (the
assembler gets confused if it prompts you for one address and you give
andther; get out before you go back).
By a fortunate stroke of luck, we happen to have guessed the right address
for the BE Q at address $ □ 3 3 F. But if we hadn't, you know how to change
it, don't you?
Check your coding, disassemble, go back to BASIC and run with a SYS
flEfl. Tap a few letter keys and note that nothing happens. Press a num-
ber; and see it appear on the screen. The program will terminate. SYS it
again and see if the RUN/STOP works. Try a BASIC loop to confirm that
BASIC and machine language work together.
Project for enthusiasts: Try modifying the program so that it checks for
alphabetic characters only. Alphabetic characters run from $<1 to $5A,
inclusive.
Things You Have Learned
—Flags are used to link instructions together. This might be an activity such
as load or compare, followed by a test such as branch on a given condition.
— Some instructions affect one or more flags, and some do not affect flags.
Thus, an instruction that sets a flag might not be followed immediately with
the instruction that tests or uses that flag.
— There are four testable flags: Z (zero, or equals); C (carry, or greater/equal);
N (negative, or high bit); and V (signed arithmetic overflow). The flags are
checked by means of "branch" instructions such as BEQ (branch equal) or
BNE (branch not equal).
— Flags are stored in the status register, sometimes called the processor status
word. The S B contains the four testable flags, plus three other flags: B (break
indicator); D (decimal mode for add/subtract); and I (interrupt lockout). The
hexadecimal value in SB can be changed to binary and used to determine
the exact condition of all flags.
— Usually, the processor is interrupted sixty times a second to do special high-
priority jobs. Everything, including the status register flags, is carefully pre-
served so that the main program can continue as though nothing had
happened.
— A number stored in memory can be considered as signed if we decide to
handle it that way. The value of a signed number is held in two's-complement
form. The high bit of the number is zero if the number is positive, one if the
FLAGS, LOGIC, AND INPUT
55
number is negative. Tlie computer doesn't care. It handies tlie bits wfiether
the number is considered signed or not, but we must write our program
l<eeping in mind tlie type of number being used.
— Tfiere are tliree logical operator instructions: AND, ORA, and EOR. Tliese
allow us to modify bits selectively within the A register. AND turns bits off;
ORA turns bits on; and EOR inverts bits, or flips them over.
Questions and Projects
Write extra coding to allow both numeric and alphabetic characters, but
nothing else.
Write a program to accept only alphabetic characters. As each ASCII
character is received, turn on its high bit with ORfl #$flD and then print
it. How has the charactef- been changed?
Write a program to accept only numeric digits. As each ASCII character
is received, turn off its lowest bit with AND #$FE and then print it. What
happens to the numbers? Can you see why?
4
Numbers,
Arithmetic,
and
Subroutines
This chapter discusses:
• Numbers: signed and unsigned
• Big numbers: multiple bytes
• Arithmetic: add and subtract
• Rotate and shift instructions
• IVIultlplication
• Home grown subroutines
57
58
MACHINE LANGUAGE FOR COMMODORE MACHINES
Numbers: Signed and Unsigned
We have looked briefly at the question of signed versus unsigned numbers.
The most important concept is that you, the programmer, choose whether
or not a number is to be considered a signed number (for a single byte,
in the decimal range -12fl to +1E7) or an unsigned integer (single-
byte range □ to 555).
It makes no difference to the computer. If you consider a number signed,
you may wish to test the sign using the N flag. If not, you won't do such
a test.
Big Numbers: Multiple Bytes
You may use more than one byte to hold a number. Again, it's your
decision. If you think the numbers may go up to a million, you might allocate
three bytes (or more or fewer). If you are doing arithmetic on multi-byte
numbers, the computer will help you by signaling in the carry flag that
there's something to be carried across from a lower byte to a higher one.
But it's up to you to write the code to handle the extra bytes.
You may size numbers by using the following table:
Unsigned: Signed:
1 byte to 255 -128 to +127
2 bytes to 65,535 -32768 to +32767
3 bytes to 16,777,215 - 8,388,608 to + 8,388,607
4 bytes to over 4 billion -2 billion to +2 billion
It's possible to work with binary fractions, but that is beyond the scope of
this book. Many applications "scale" numbers, so that dollar-and-cents
amounts are held as integer quantities of pennies. Thus, two bytes un-
signed would hold values up to $fc55,35, and three bytes up to
$lt7,7?E.15.
When signed numbers are held in multiple bytes, the sign is the highest
bit of the highest byte only.
We will concentrate on single-byte arithmetic principles here, touching on
multiple-byte numbers as a generalization of the same ideas.
Addition
Principles of addition are similar to those we use in decimal arithmetic;
for decimal "columns," you may substitute "bytes." Let's look at a simple
decimal addition:
NUMBERS, ARITHMETIC, AND SUBROUTINES
59
Rule 1 : We start at the right-hand column (the low-order byte).
Rule 2: We add the two values, plus any carry from the previous column. A new
carry may be generated; it can never be greater than one. (ADC includes any
carry from a previous activity, and may generate a new carry bit, which is either
or 1.)
Rule 3: When we start at the right-hand column, there is no carry for the first
addition. (We must clear the carry with CLC before starting a new addition.)
Rule 4: When we have finished the whole addition, if we have a carry and no
column to put it in, we say the answer "won't fit." (If an addition sequence of
unsigned numbers ends up with the carry flag set, it's an overflow condition.)
HIGH BYTE
00101011
00001010
LOW BYTE
10111001 y
11100101 X
START:
NO CARRY
00110110
/
CARRY
/
10011110
Figure 4.1
How do we translate these rules into machine language addition?
1 . Before we start an addition sequence, clear the carry with CLC .
2. If the numbers are more than one byte in size, start at the low byte and work
up to the high ones. Addition will take place in the A register only; you may
add the contents of an address or an immediate value. The carry flag will
take care of any carries.
3. When the addition sequence is complete, check for overflow:
a) If the numbers are unsigned, a set C flag indicates overflow;
b) if the numbers are signed, a set V flag indicates overflow.
Thus, to add two unsigned numbers located at addresses $D3fiD and
$□361 and to place the result at $ 033 5, we might code
60
MACHINE LANGUAGE FOR COMMODORE MACHINES
CLC
LDa $D3flD
RDC $03ai
STft $D3flE
We might also BCS to an error routine, If desired.
To add a two-byte number located at $ □3RD (low) and $D3ftl (high)
to another two-byte number located at $D3Bn (low) and $ 0381 (high),
placing the result at $D3CD/1, we might code
CLC
LDa $D3ftD
aDC $D3BD
STa $D3cn
LDa $D3ai
aOC $03B1
STa $D3C1
Again, we might BCS to an overflow error routine.
If we had two-byte signed numbers in the same locations, we'd add them
exactly the same way, using the same code as above. In this case, how-
ever, we'd check for overflow by adding the instruction BVS, which would
branch to an error routine. The carry flag would have no meaning at the
end of the addition sequence.
Subtraction
Subtraction might be defined as "upside down" addition. The carry flag
again serves to link the parts of a multibyte subtraction, but its role is
reversed. The carry flag is sometimes called an "inverted borrow" when
used in subtraction. Before performing a subtraction, we must set the C
flag with SEC. If we are worried about unsigned overflow, we look to
confirm that the carry is set at the completion of the subtraction operation.
If the carry is clear, there's a problem.
Thus, to perform a subtraction, we follow these rules:
1. Before we start a subtraction sequence, set the carry with SEC.
2. If the numbers are more than one byte in size, start at the low byte and^work
up to the high ones. Subtraction will take place in the ft register only; you
may subtract the contents of an address or an Immediate value. The C flag
will take care of any "borrows."
3. When the subtraction sequence is complete, check for overflow:
a) if the numbers are unsigned, a clear C flag indicates overflow;
NUMBERS, ARITHMETIC, AND SUBROUTINES
61
b) if the numbers are signed, a set V flag indicates overflow.
Thus, to subtract two unsigned numbers located at addresses $D3flD
and $ 0361 and to place the result at $ DBA 5, we might code
SEC
LDfi $D3fiO
SBC $D3fll
STa $U3&E
A BCC could go to an error routine.
Comparing Numbers
if we have two unsigned numbers and wish to know which one is larger,
we can use the appropriate compare instruction— CMP, CPX, or CPY—
and then check the carry flag. We've done this before. If the numbers are
more than one byte long, however, it's not quite so easy. We must then
use a new technique.
The easiest way to go about such a comparison is to subtract one number
from the other. You need not keep the result; all you care about is the
carry flag when the subtraction is complete. If the C flag is set, the first
number (the one you are subtracting from) is greater than or equal to the
second number. Why? Because carry set indicated that the unsigned
subtraction was legal; we have subtracted the two numbers and have
obtained a positive (unsigned) result. On the other hand, if the C flag ends
up clear, this would mean that the first number is less than the second.
The subtraction couldn't take place correctly since the result— a negative
number — can't be represented in unsigned arithmetic.
Left Shift: Multiplication by Two
If we write the decimal numbers and EDO in binary, we see an
interesting pattern:
EDO: ^IIODIDDO
To double the number, each bit has moved one position to the left. This
makes sense, since each bit has twice the numeric "weight" of the bit to
its right.
The command to multiply a byte by two is ASL (arithmetic shift left). A
zero bit is pushed into the low (or "right") side of the byte; all bits move
62
MACHINE LANGUAGE FOR COMMODORE MACHINES
left one position; and tlie bit that "falis out" of tlie byte— in this case, a
zero bit— moves into the carry. It can be diagrammed iil<e this:
IN AN ASL (ARITHMETIC SHIFT LEFT), EACH BIT
MOVES ONE POSITION LEFT. A ZERO MOVES INTO THE
LOW-ORDER BIT.
Figure 4.2
That's good for doubling the value of a single byte, if a "one" bit falls into
the carry flag, we can treat that as an overflow. What about multiple bytes?
It would be ideal if we had another instruction that would worl< just lil<e
aSL. Instead of pushing a zero bit into the right hand side of the byte,
however, it would push the carry bit, that is, the bit that "fell out" of the
last operation. We have such an instruction: ROL.
ROL (rotate left) works exactly iil<e ASL except that the carry bit is pushed
into the next byte. We can diagram it as follows:
CARRY
IN A ROL (ROTATE LEFT), THE CARRY MOVES INTO
THE LOW ORDER BIT; EACH BIT MOVES LEFT; AND THE
HIGH ORDER BIT BECOMES THE NEW CARRY.
Figure 4.3
Thus, we can hook two or more bytes together. If they hold a single
multibyte number, we can double that number by starting at the low-order
end. We ASL the first value and ROL the remainder. As the bits fall out
of each byte, they will be picked up in the next.
Multiplying by two may not seem too powerful. We can build on this starting
point, however, and arrange to multiply by any number we choose.
CARRY
(C FLAG)
ASL
CARRY
Multiplication
NUMBERS, ARITHMETIC, AND SUBROUTINES
63
ROL
fi
ASL
, , H +
ROL r-[I^^^3-^ LOW ORDER BYTE
■ - - > -h c
HIGH ORDER BYTE
TO MULTIPLY A THREE-BYTE NUMBER BY TWO, WE
SHIFT THE LOW ORDER BYTE WITH ASL; THEN WE USE
ROL TO ALLOW THE C FLAG TO "LINK" FROM ONE
BYTE TO THE NEXT.
Figure 4.4
We won't deal with a generalized multiplication routine here, but a couple
of specific examples can be shown.
How can we multiply by four? Multiply by two, twice. How can we multiply
by eight? Multiply by two, three times.
Here's an important one. We often want to multiply by ten. For example,
if a decimal number is being typed in at the keyboard, the number will
arrive one digit at a time. The user might type Ell, for example. The
program must then input the two and put it away; when the one arrives,
the two must be multiplied by ten, giving twenty, and the one added; when
the seven is typed, the twenty-one must be multiplied by ten before the
seven is added. Result: 517 in binary. But we must first know how to
multiply by ten.
To multiply by ten, you first multiply by two; then multiply by two again.
At this point, we have the original number times four. Now, add the original
number, giving the original number times fivd. Multiply by two one last
time and you've got it. We'll see an example of this in Chapter 7.
Right Shift and Rotate: Dividing by Two
If we can multiply by two by shifting (and rotating) left, we can divide by
two by moving the bits the other way. If we have a multibyte number, we
must start at the high end.
LSR (logical shift right) puts a zero into the left (high-order) bit, moves all
the bits over to the right, and drops the leftover bit into the carry. ROR
(rotate right) puts the carry bit into the left bit, moves everything right, and
64
MACHINE LANGUAGE FOR COMMODORE MACHINES
T — I — r
LSR
—I—
T — I — r
J I I i_i L
C FLAG
IN AN LSR, ZERO MOVES INTO THE HIGH BIT, AND ALL
BITS MOVE RIGHT ONE POSITION; THE LOWEST BIT
BECOMES THE CARRY.
ROR
9 r
T 1 1 1 — I 1 1 — I
I I L
J I I l_l
c
IN A ROR, THE CARRY MOVES INTO THE HIGH BIT AND
ALL BITS MOVE RIGHT ONE POSITION; THE LOWEST
BIT BECOMES THE NEW CARRY.
LSR
ROR
C H-
ROR
C
TO DIVIDE A THREE-BYTE NUMBER BY TWO, WE SHIFT
THE HIGH-ORDER BYTE WITH LSR; THEN WE USE ROR
TO ALLOW THE C FLAG TO "LINK" FROM BYTE TO
BYTE.
Figure 4.5
drops the leftover bit into ttie carry once again. At the end of a right-shifting
sequence, the final carry bit might be considered a rema/nc/er after dividing
by two.
Comments on Shift and Rotate
As you might expect of arithmetic instructions, the shift and rotate instruc-
tions normally operate in the A register. But there's an extra bonus: these
instructions also can operate directly on memory. In other words, the
computer can go to any address in memory and shift the bits at that address
directly, without loading the data into a register.
For this reason, you'll often see the instructions coded with the identity of
the A register coded in the address part of the instruction. We would code
NUMBERS, ARITHMETIC, AND SUBROUTINES
65
LSR A so as to distinguish from LSB $1E3A, where the contents of
memory is being shifted.
When a rotate or shift is performed directly on a memory location, the Z,
N, and C flags are affected according to the contents of memory. Z will
be set if the contents of the location ends up as zero; N if the high bit is
set; and C performs its standard role of catching the leftover bit.
Some programmers wonder about the terms logical and arithmetic, used
as part of the definition. The distinction is related to the way that signed
numbers are treated. "Logical" means that the sign of a number will prob-
ably be lost if the number was intended to be signed. "Arithmetic" means
that the sign will probably be preserved. It's purely a terminology question:
the bits themselves move exactly as you would expect them to do.
Subroutines
We have written programs that are subroutines called by BASIC. We have
written subroutine calls to built-in operations such as $FFD2 or $FFE<.
Can we also write our own subroutine and arrange to call it?
Of course we can. RTS (return from subroutine) does not mean "return
to BASIC." It means "return to whoever called this routine." If BASIC
called up the machine language routine, RTS takes you back to BASIC.
If another machine language program called up the subroutine, RTS will
return to the calling point.
We wrote a useful subroutine in the last chapter. Its purpose was to accept
only numeric keys, echo them to the screen, and convert the ASCII value
to binary. Now we'll use this subroutine to build a more powerful program.
Here it is. Be sure it's entered in your computer.
A
□ 33C
JSR
$FFE1
A
033F
BEQ
$□351
A
□ 341
JSR
$FFE4
A
D3AA
CMP
#$30
A
D3Ay
BCC
$^33C
A
D3A&
CMP
#$3A
A
□ 34A
BCS
$^33C
A
Q3AC
JSR
$FFD2
A
034F
AND
#$^F
A
0351
RTS
66
MACHINE LANGUAGE FOR COMMODORE MACHINES
The Project
Here is our mission: using tlie above subroutine, we wisli to build a simple
addition program. Here's how we want it to work. The user will touch a
numeric l<ey, say "3". Immediately, "3 + " will appear on the screen.
Now the user will touch another key, say "A", and the program will
complete the addition so that the screen shows " 3 + = 7 " . We will
assume that the total is in the range to R so that we don't have to worry
about printing a two-digit answer— don't try 5 + 5 or you'll get a wrong
answer.
0128 note: Remember to check Appendix E, Exercises for the Commo-
dore 128, for the appropriate coding.
Here we go. We must start our coding at address $0355 so as not to
disturb our subroutine. We'll need to give SYS 350 to make this one go.
A 0355 JSR $D33C
We call our prewritten subroutine, which waits for a numeric key, echos
it to the screen, and converts the value to binary in the A register.
Our next action is to print the plus sign. We know how to do this, once
we look up the ASCII code for this character. Appendix D tells us that it's
$EB, so we'll need to LDft #$5B and JSR $FFD2. But wait a minute!
Our binary value is in the A register, and we don't want to lose it. Let's
store the value somewhere:
A 0355 STA $03CD
A □35a LDA #$EB
A □35A JSR $FFD2
A 0350 JSR $Q33C
We picked $03 CO, since nobody seems to be using it, and put the binary
number safely away there. Now we print the plus sign, and go back to
ask for another digit.
When the subroutine returns, it has a new binary value in the A register;
the digit has been neatly printed on the screen behind the plus sign. Now
we need to print the equal sign. But again, wait! We must put our binary
value away first.
We could place the value into memory — perhaps $03C1 would do — but
there's another way. We don't seem to be using X or Y for anything at
NUMBERS, ARITHMETIC, AND SUBROUTINES
67
the moment, so let's slip the value across into one or the other. We have
four "transfer" commands that will move information between A and either
index register:
Like the load series of commands, these instructions mal<e a copy of the
information. Thus, after TAX, whatever information was in fi is now also
in X. Again like the load commands, the Z and N status flags are affected
by the information transferred, it doesn't matter whether we use X or Y.
Let's pick X:
a DabD TAX
A DBbl LDA#$3D
A 03fc3 JSR $FFD2
We have put our second value into X and printed the equal sign ($BD).
Now we can bring the value back and do our addition. The next two
instructions can come in any order:
A DBtb TXA
A 03fc7 CLC
A OBbfl ADC $D3CD
We have our total in the A register. It's almost ready to print, except for
one thing: it's in binary. We want it in ASCII.
Assuming the total is in the range to "=1, we can convert it directly to a
single ASCII digit with an OR A operation. (If it's greater than nine, you're
cheating and the answer won't make sense.)
A Q3LB ORA #$3D
A a3tD JSR $FFDE
Are you basically a neat person? Then you'll want to print a RETURN to
start a new line:
A □370 LDA #$DD
A 0372 JSR $FFD5
A 0375 RTS
Check it with a disassembly. If you disassemble starting with the subrou-
tine, you'll need more than one screen full of instructions to see it all. No
problem. When the cursor flashes at the bottom of the screen, press the
letter D and RETURN and you'll see a continuation of the listing.
TAX— Transfer A to X
TRY— Transfer A to Y
TY A— Transfer Y to A
TXA— Transfer X to A
68 MACHINE LANGUAGE FOR COMMODORE MACHINES
Back to BASIC. This time we do nof give SYS flEfl—tliat's the subroutine
and we want the main routine, remember?
Give the SYS flSO command. Tap a couple of numeric keys that total
nine or less. Watch the results appear instantly on the screen.
If you like, set up a BASIC loop and call the routine several times.
Project for enthusiasts: You couldn't resist, could you? You had to type
in two digits that totaled over 9 and got a silly result. OK, your project is
to try to expand the above code to allow for two-digit results. It's not that
hard, since the highest possible total is ■=! + R or Ifl; so if there are two
digits, the first one must be the digit 1. You'll need to compare for the
result over binary nine, and then arrange for printing the one and sub-
tracting ten if necessary. Sounds like fun.
Things You Have Learned
— We may decide to use a number as a signed value; in this case, the high bit
of the number will be □ if the number is positive and 1 if the number is
negative. It's up to us. As far as the computer is concerned, it's just bits in
either case.
—When a number might have a value that won't fit into an eight-bit byte, we
may use more than one byte to hold the value. We have already done this
to hold addresses in two bytes: there's a high byte to hold the high part of
the value and a iow byte to hold the low part.
—We may add two numbers together using the ADC instruction with the a
register; we should always clear the carry flag before starting an addition.
The carry flag will take care of multibyte numbers for us, providing we re-
member to start the addition at the low end.
—We may subtract two numbers using the SBC instruction with the a register;
we should always set the carry flag before starting a subtraction. The carry—
which is sometimes called an inverted borrow— \n\\\ take care of multibyte
numbers for us, providing we remember to start the subtraction at the low
end.
— For unsigned numbers, the carry should end up as it started (clear for addition,
set for subtraction); otherwise we have overflow in the result. For signed
numbers, the carry doesn't matter; the V flag will be set if we have overflow.
—We may multiply a byte by two with the aSL (arithmetic shift left) instruction.
If we have a multiple-byte number, we may carry the multiplication through
to other bytes by using the ROL (rotate left) instruction, starting at the low
byte of the number.
— We may divide a byte by two with the LSE (logical shift right) instruction. If
we have a multiple-byte number, we may carry the division through to other
NUMBERS, ARITHMETIC, AND SUBROUTINES
69
bytes by using the ROR (rotate right) instruction, starting at the high byte of
the number.
—The shift and rotate instructions may be used on the contents of the A register
or directly on memory. The N and Z flags are affected, and the C flag plays
an important role in the shift/rotate action.
—If we wish to multiply by a value other than two, we may need to do more
work but we can get there.
—As we might have expected, we may write subroutines in machine language
and then call them from machine language. It's a good way to organize your
code.
Questions and Projects
Write a program to subtract two single-digit numbers, similar to the one
in the above exercise. You may continue to use the subroutine from the
previous chapter.
Write a program to input a single-digit number. If the number is less than
five, double it and print the result. If the number is five or over, divide it
by two (discarding any remainder) and print the result. Try to produce a
neat output.
Write a program to input a single-digit number. Print the word ODD or
EVEN behind the number, depending on whether it is odd or even. Use
the LSR instruction followed byaBCCorBCS test to check for odd or
even.
If you've been following the logic, you have developed quite a bit of ca-
pability in machine language. You can input, you can output, and you can
do quite a bit of arithmetic in between.
By now, you should have developed skills with the machine language
monitor and feel much more comfortable zipping in and out. These skills
are not difficult, but they are important to the beginner. Without them, you
can never get comfortably into the real meat: how to code machine lan-
guage itself.
5
Address
Modes
This chapter discusses:
• Non-addresses: implied, immediate, register
• Absolute and zero-page
• Indexing
• The relative address for branches
• Indirect addressing
• Indirect, indexed
71
72
MACHINE LANGUAGE FOR COMMODORE MACHINES
Addressing Modes
Computer instructions come in two parts: tlie instruction itself, or op code,
and the address, or operand. Tfie term "address" is a little misleading,
since sometimes the operand does not refer to any memory address.
The term address mode refers to the way in which the instruction obtains
information. Depending on how you count them, there are up to 13 ad-
dress modes used by the 650x microprocessor. They may be summarized
as follows:
1. No memory address: Implied, accumulator.
2. No address, but a value supplied: immediate.
3. An address designating a single memory location: absolute; zero-page.
4. An indexed address designating a range of S 5 fc locations: absolute,x; ab-
solute,'^; zero-page,x; zero-page.y.
5. A location in which the real (two-byte) jump address may be found: indirect.
6. An offset value (e.g., fonward "R, back 17) used for branch Instructions:
relative.
7. Combination of indirect and indexed addresses, useful for reaching data
anywhere in memory: indirect, indexed; indexed, indirect.
No Address: Implied Mode
Instructions such as INX (increment X), BRK (break), and TfiY (transfer
a to Y) need no address; they make no memory reference and are com-
plete in themselves. Such instructions occupy one byte of memory.
We might say that such instructions have "no address." The precise term
is "implied address," which seems to say that there is in fact an address
but we do not need to state it.
Perhaps the word "implied" is usecj in this manner: an instruction such as
INX implies the use of the address register; and an instruction such as
BRK implies the address of the machine language monitor. If so, there's
an instruction that still defies this definition: NOP.
The Do-Nothing Instruction: NOP
NOP (no operation) is an instruction that does nothing. It affects no data
registers or flags. When a NOP instruction is given, nothing happens and
the processor continues to the next instruction. It seems inappropriate to
ADDRESS MODES
73
me that we say that NOP has an implied address. It doesn't do anything;
it doesn't have an address at all. On the other hand, I suppose that logicians
might say, "Yes, but it does nothing to the X register."
The NOP instruction, whose op code is lEA, is surprisingly useful. It's
not simply that if you're a contract programmer getting paid by the byte
you might be tempted to put a large number of NOP instructions into your
program. NOP can serve two important program testing functions: taking
out unwanted instructions, or leaving space for extra instructions.
It's not as easy to change a machine language program as it is to change
a BASIC program. As you have seen, the instructions are placed in specific
locations, if we wish to eliminate an instruction, we must either move all
the following instructions down or fill in the space with NOP instructions.
If we move the instructions, we may need to correct some of the addresses.
Examine the following code:
□ 350 LDA#$DD
D3SE STA $123<
□ 355 ORfi $3ASy
If we decide to eliminate the instruction at D355 (STfi $123^), we must
remove all three bytes. So we place code $Ea in locations D352, 0353,
and 035<.
Suppose we are testing a moderately large program. Most programs will
break into distinct "modules," each of which does a specific job. One
module might clear a portion of memory to zero, another might do a
calculation, and so on. When we are checking out this program, It might
be wise to look at each module as it runs.
In this case, we might deliberately code a BRK (break) command between
each program module. The program will start to run, and then it will break
to the machine language monitor. Within the monitor, we can examine
memory to ensure that this module has done the job as we planned it.
When we are satisfied, we can start the next module using the . G com-
mand. In this way, we can have tight testing control over our program.
That's all very well, but when we have finished testing our program and
are satisfied that it runs correctly, we don't want the BRK instructions
there. That's easy to fix. We replace the BRK codes ($□□) with NOP's
($E&), and the program will run through to the end.
If we are writing a program and suspect that we may need to insert one
or two extra instructions within a certain area of the code, we can put a
74
MACHINE LANGUAGE FOR COMMODORE MACHINES
number of NOP instructions there. Tlie space will be available for use
when we need it.
No Address: Accumulator Mode
We have observed that the shift and rotate instructions, aSL, ROL,
LSE / and ROR, allow data manipulation in either the A register of directly
in memory. When we want to use the A register, or accumulator, you
should note this fact as you code your program. For example, you would
write ftSL R or sometimes just ASL.
Where accumulator mode addressing is used, it has the same character-
istics as implied addressing: the whole instruction fits into one byte.
Where the shift/rotate instruction refers to a memory location, an address
will of course be needed. These address modes will be described later.
Other than the shift and rotate instructions, there is one other set of in-
structions that manipulates memory directly. You may recall INX, INY,
DEX, and DEY increment or decrement an index register.
INC (increment memory) adds one to any memory location. DEC (dec-
rement memory) subtracts one from any memory location. Both instruc-
tions affect the Z and N flags.
When an instruction modifies memory, the address mode is neither Implied
nor accumulator. Memory reference addressing will be discussed later.
Not Quite an Address: Immediate Mode
Coding such as LDR #$3-^ does not reference a memory address. In-
stead, it designates a specific value (in this case, $3^). An instruction
with Immediate addressing takes up two bytes: one for the op code and
the second for the immediate value.
We have used immediate addressing several times. It has a "natural" feel,
and it's fast and convenient. There is one potential pitfall: immediate ad-
dressing is so easy to use that it may be abused. Each time you code an
immediate address, ask yourself, "Could this value ever change?" By
writing a value into a program, rather than a variable, you may be freezing
that value forever.
An example: a program is written for a VIC-20, which has EE columns on
the screen. At various places In the program, values are compared to EE
(hex lb), and EE is added or subtracted to various screen addresses. In
ADDRESS MODES
75
each case, immediate mode addressing is used to provide the value of
EE. Some time later, the programmer decides to convert to the Com-
modore 64, which has A D columns on the screen. The programmer must
change each immediate mode reference from EE to (hex Efi).
If the value EE had been stored in a memory location so as to be used
as a variable, all this receding would not be needed. The moral is clear:
excessive use of immediate mode can call for extra programming work at
a later time.
There are certain instructions for which immediate addressing is not pos-
sible. For example, we can LDfi #$00, that is, bring in the actual value
zero rather than the contents of an address, but we cannot ST A imme-
diate — we must store the information somewhere in memory.
A Single Address: Absolute Mode
An instruction might specify any address within memory — from $0000
to $FFFF— and handle information from that address. Giving the full
address is called absolute addressing; if you like, you can deal with in-
formation absolutely anywhere in memory.
MEMORY
Figure 5.1 Absolute Mode Specifies One Address Anywhere Witliin IMemory.
We have used absolute addresses several times. When we exchanged
the contents of memory locations $03fl0 and $D3fil, we named these
addresses as we used them. When we stored a value from the keyboard,
we named location $OBCD. We have also used absolute addresses for
program control: subroutines at$FFDEand$033C were called up sim-
ply by giving the address.
The JSR (jump subroutine) instruction calls up a subroutine anywhere in
memory by using absolute addressing. There is also a JMP (jump) in-
struction, which can transfer program execution to any location in memory;
it's similar to the BASIC GOTO statement. JMP can use absolute ad-
dressing — it can go anywhere.
There's a limitation to absolute addressing, however. Once you have writ-
ten the instruction, you can go only to the address stated. You cannot
reach a range of locations; only one.
One-location addressing can be good for any of several jobs. On the PET/
76
MACHINE LANGUAGE FOR COMMODORE MACHINES
CBM, we might want to switch between text and graphics modes by ma-
nipulating address 5 R ^ t fl (hexadecimal E fl 4 C) . On the VIC-20, we might
lil<e to set the volume level of the sound generator by placing a value into
location BfcflTfl (hex nODE). On a Commodore 64, the screen's back-
ground color can be changed by manipulating address SBEfll (hex DD21).
In each case, it's one specific address that we want; absolute addressing
will do the job for us. And we will also use absolute addressing to reference
the various RAM locations that we have picked for our own program "var-
iables."
Zero-Page Mode
A hexadecimal address such as $aBai is sixteen bits long and takes up
two bytes of memory. We call the high byte (in this case, $03), the
"memory page" of the address. We might say (but usually don't) that this
address is in page 3 at position $fil.
$□□ $FF $!□□
Figure 5.2 Zero-Page Mode Specifies A Single Address from $□□ to $FF.
Addresses such as $QQAC and lODF? are in page zero; in fact, page
zero consists of all addresses from $□□□□ to $DOFF. Page-zero lo-
cations are very popular and quite busy. There's an address mode spe-
cially designed to quickly get to these locations: zero-page addressing.
We may think of it as a short address, and omit the first two digits. Instead
of coding LDA $DO'^D,we may write LDA and the resulting code
will occupy less space and run slightly faster.
Zero-page locations are so popular that we'll have a hard time finding
spare locations for our own programs. As a result, we tend to conserve
zero-page Ipcations on Commodore machines. We'll need the few that
are available for a special addressing mode, indirect, indexed, that will
be discussed later.
There are many locations in zero page that are useful to read. For example,
the BASIC system variable ST, which is important in input/output handling,
may be examined there (location $Rt. in PET/CBM, location $"=10 in VIC-
20 and Commodore 64). If you need to know whether the user is holding
down a key, there's an address in zero page that will tell you that (location
$q7 in PET/CBM, $CB in VIC and 64, $DA in C128).
Zero-page addressing, like absolute addressing, references one location
ADDRESS MODES
77
only. It's good for a specific vaiue; but for a range of values we need
something more.
A Range of 5 5 b Addresses: Absolute,
Indexed Mode
Indexing has already been used in Chapter 2. We give an absolute ad-
dress, and then indicate that the contents of X or Y should be added to
this address to give an effective address.
Figure 5.3
Indexing is used only for data handling: it's available for such activities as
load and store, but not for branch or jump. Many instructions give you a
choice of X or Y as an index register; a few are limited specifically to X
or Y. Instructions that compare or store X and Y (CPX, CPY, STX, and
STY) do not have absolute, indexed addressing; neither does the BIT
instruction.
An instruction using absolute, indexed addressing can reach up to 25 b
locations. Registers X and Y may hold values from □ to 255, so that the
effective address may range from the address given to 555 locations
higher. Indexing always increases the address; there is no such thing as
a negative index when used with an absolute address. If the address given
is above $FFDO, a high value in the index may cause the address to
"wrap around" and generate an effective address In the region of $ □ □ □ ;
othenwise, the effective address is never lower than the instruction ad-
dress.
We've seen the use of indexing. An instruction can reference a certain
address, then, as the program loops or as the need for information changes,
the same instruction can reference the contents of a different address.
The maximum range of E5ti locations is an important limitation.
^--^1ndex
VALUE
BASE
ADDRESS
78
MACHINE LANGUAGE FOR COMMODORE MACHINES
The "reach" of an absolute, indexed instruction allows it to handle infor-
mation in buffers (such as the input buffer, keyboard buffer, cassette buffer);
tables (such as the active file table); and short messages (such as HELLO
or error messages). It's not big enough, however, to reach all parts of
screen memory, all parts of a BASIC program, or all of RAM. For that,
we'll use indirect, indexed addressing, which will be described later.
All of Zero Page: Zero-Page, Indexed
Zero-page, indexed addressing seems at first glance to be similar to the
absolute, indexed mode. The address given (this time in zero-page) has
the contents of the selected index added to it. But there's a difference: in
this case, the effective address can never leave zero page.
This mode usually uses the X register; only two instructions, LDX and
STX, use the Yregister for zero-page, indexed addressing. In either case,
the index is added to the zero-page address; if the total goes beyond zero
page, the address "wraps around." As an example, if an instruction is
coded LDa $ED , X and the X register contains 5Q at the time of exe-
cution, the effective address will be $□ 030. The total ($ED + $50 or
$130) will be trimmed back into zero page.
$00
$FF
BASE
ADDRESS
Figure 5.4
Thus, any zero-page address can be indexed to reach any other place in
zero page; the reach of EEb locations represents the whole of zero page.
This creates a new possibility: with zero-page, indexed addressing, we
can achieve negative indexing. For this address mode only, we can index
in a downward direction by using index register values such as $FF for
- 1, $FE for - E, and so on.
On Commodore machines, zero page is fairly well occupied. There is
limited opportunity to use zero-page, indexed addressing.
ADDRESS MODES
79
Branching: Relative Address Mode
We have written several branch instructions already; the assembler al-
lowed us to enter the actual addresses to which we want to branch. The
assembler translates it to a different form — the relative address.
Figure 5.5
Relative address means, "branch forward or backwards a certain number
of bytes from this point." The relative address is one byte, making the
whole instruction two bytes long. Its value is taken as a signed number.
A branch instruction with a relative address of $05 would mean, "if the
branch is taken, skip the next 5 bytes." A branch instruction with a relative
address of $F7 would mean, "if the branch is taken, back up ^ bytes
from where you would othenwise be." As a signed number, $F7 is equal
to a value of -R.
We can calculate a branch by performing hexadecimal subtraction; the
"target" address is subtracted from the PC address. If we have a branch
at $ □ 3 4 1 that should go to $ □ 3 3 C, we would work as follows: $ 3 3 C
(the target) minus $03^3 (the location following the branch instruction)
would give a result of or minus 7. This is tedious to do, and often
results in mistakes; such mistakes in calculating a branch address are
often fatal to the program run. We are much better off using an assembler
to work out the arithmetic for us.
The longest branches are: $ 7 F, or 157 locations ahead; and $flD, or
IE a locations back. This poses no difficulties with short programs, such
as the ones we are writing here. But in larger programs, the branch may
not be able to reach far enough. The usual solution to this is to place a
JMP (jump) instruction nearby, which is capable of going anywhere in
memory; JMP uses absolute addressing. The appropriate branch instruc-
tion will go to the JMP, which in turn will take the program to the desired
location.
Advocates of programming style make the following argument. All pro-
grams should be written into neat small modules. Logic blocks should be
80
MACHINE LANGUAGE FOR COMMODORE MACHINES
broken into subroutines, and tlie subroutines into even smaller subrou-
tines; this way, everything is neat and testable. If you should find a branch
that won't reach, ask yourself whether it's time to break your program into
smaller chunks before the logic gets too messy. By the liberal use of
subroutines, you can arrange your code so that all branches are short and
easily within reach. If you do break up the program structure, the branches
will then always reach. It's up to you to choose your coding style, but you
might give the question some thought.
An interesting aspect of relative addressing is that code containing branches
is easy to relocate. A piece of code containing a branch to six locations
ahead will work perfectly if the whole code is moved to a different location.
This is not true of jumps and subroutine calls, or any code using absolute
addressing— if the location changes, the address must be changed.
TheROm Link— Jumps in Indirect Mode
We have mentioned the J MP instruction that will take the program to any
specified address. JMP has another address mode: indirect addressing.
Indirect addressing is signaled by the use of parentheses around the
address. It works this way. An address is supplied, but It's not the one we
will eventually use. We take this address, and at the location it specifies,
we'll find the effective address, or the indirect address. The indirect ad-
dress is two bytes long, of course, and is stored in the usual 650x manner
of low byte first.
An example will help to make things clear. Suppose that at address $D33C
we have the instruction JMP ($153^^). The parentheses tell us that in-
direct addressing is involved. The machine code is hex tC 3 A 12; as
always, the address is "turned around." Now suppose that at addresses
$1S34 and $1235 we have stored values $EA and $tfl. The jump
instruction would behave as follows: it would go to $1234 and $1235,
get the contents, and the program would transfer to address $fcflE<.
INDIRECT
ADDRESS
Figure 5.6
ADDRESS MODES
81
The JMP indirect has a somewhat specialized use. Normally, if we want
to transfer control to some location, we just JMP there; no need for the
indirect step. But there's one quite important case where indirect jumps
serve an important function.
Within ROM, there are a large amount of permanent instructions that the
computer uses to perform its tasks. Since it's in ROM, we can never change
this code. If the various programs were linked only by means of JMP and
JSR statements, they could not be changed, and we would not be able
to modify the behavior of the machine.
Built into the ROM program, there are a series of carefully planned indirect
jumps. Instead of the ROM leaping from one instruction directly to another,
it jumps indirectly via an address stored in RAM. We can change the
contents of RAM; and if we change the address stored in RAM, we can
modify the behavior of the system. The best-known indirect address is
that associated with the interrupt sequence: it's at $OD'=ID in PET/CBM
and $D31< in VIC, 64, PLUS/4, and C128.
You might not code many indirect jumps, but you'll be glad that they are
there in ROM.
Data From Anywhere: Indirect, Indexed
The problems with indexed addressing have been noted: the reach of only
E5L bytes limits the data capability of this method.
Indirect addressing seems to offer a total solution. We can write an in-
struction that points at an indirect address. Since we can change the
indirect address at will, or add to or subtract from it, we can cause our
instruction to deal with data anywhere in memory.
In fact, we get a limitation and a bonus. First, the limitation: for indirect,
Indexed instructions the indirect address must be in zero-page — two bytes,
of course, organized low byte first, as always. Next, the bonus: after the
indirect address is obtained, it will be indexed with the Y register to form
the final effective address.
Let's step our way through the mechanism and see how it works. Suppose
I code LDA ($CD). Y with values $11 in address IDDCD and $B2 in
address $0DC1. If the Y register contains a value of 3, the instruction
will follow these steps: The address of $DDCD/1 is extracted, giving
'$5211; then the contents of Y are added to give the effective address
of If the contents of Y changed, the effective address would
82
MACHINE LANGUAGE FOR COMMODORE MACHINES
change slightly. If the indirect address at $CD and $C1 was changed,
the effective address would change radically.
The combination of indirect and indexing may seem lil<e overl<ill. If you
can designate any location in memory with an indirect address, why bother
with indexing? After ail, anywhere plus one is still anywhere.
Indirect addressing plus indexing proves to be an ideal combination for
the manipulation of data. Almost all data breaks up into logical chunks of
some sort: records, table entries, screen lines, words, and so on. Here's
the technique. We position the indirect address at the start of a given
logical data chunk, and use the Y register to scan through the information.
When we're ready to move to the next item, we move the indirect address
along, and repeat the same scanning of the Y register through the new
data.
00
FF
INDIRECT,
INDEXED"
rv i I
Figure 5.7
One may think of it as a fishing analogy: We anchor the boat in a certain
spot (fix the indirect address) and then use the fishing line (the Y register)
to reach the data we need. When we're ready for the next item, we pull
up the anchor and move along to a new place.
■DATA IN MEMORY-
NAME, ETC.
NAME, ETC.
NAME, ETC.
A E
3
Figure 5.8
We'll be working through an elaborate example that uses indirect, indexed
addressing to manipulate the computer screen. First, a brief diversion.
ADDRESS MODES
83
A Rarity: Indexed, Indirect
There is another addressing mode that is little used in Commodore com-
puters: indexed, indirect. It uses the X register rather than the Y, and is
coded as in the following example: LDA ($CD , X). In this case, indexing
takes place first. The contents of X are added to the indirect address (in
this case, $CD) to mal<e an effective indirect address. If X were equal to
A in this example, the effective indirect address would be SOQCA, and
the contents of $OQCA and $DDC5 would be used as the effective
address of the data.
$00
$FF
1
INDEXED, INDIRECT ALLOWS ONE OF SEVERAL
INDIRECT ADDRESSES TO BE CHOSEN USING
THE X INDEX REGISTER
Figure 5.9
In certain types of control processing, this is a quite useful address mode.
X will contain an even number; since each indirect address is two bytes
long, we will need to skip from one to the other, two bytes at a time.
Let's take a hypothetical communications system that is connected to four
telecommunications lines and see how indexed, indirect addressing might
be used. Characters are being received from the four lines almost simul-
taneously. As each character arrives, it must be put away into a memory
buffer belonging to that particular line; in that way, traffic received from
the various sources won't get mixed together. Zero-page will contain four
indirect addresses, one for each line; each indirect address points at an
input area for one line. Suppose a character is received into the A register
from one of the lines; the line number (times two) is in the X register. We
84
MACHINE LANGUAGE FOR COMMODORE MACHINES
could then put the character away with the instruction STft ($tO,X).
Thus, if line zero was involved, its indirect address at address $bQ/tl
would be used; for line 1, the address at $bE/b3 would be used; and
so on. After we had stored the character concerned, we'd need to bump
the indirect pointer so that the next character will go into a new position:
INC $tiD , X would do the trick.
The above example is a rather specialized use of the indexed, indirect
address mode. You may never need to use this mode. Indeed, most
programmers lead full, rich lives without ever writing code that uses in-
dexed, indirect addressing.
The Great Zero-Page Hunt
Indirect, indexed addresses are very important. They are your gateway to
reaching any part of memory from a single instruction. But you must have
two bytes available in zero-page for each indirect address you want to
use.
The Commodore ROM system helps itself to liberal amounts of zero-page
memory. You don't have much empty space left over. How can you find
space for these indirect pointers?
First, look for unused locations. There are only a few of them: on the VIC
and Commodore 64, you'll find four locations at locations $DOFCto$DDFF.
That's enough for two indirect addresses.
If you need more, look through the memory maps for locations designed
as "work areas" or "utility pointers." They can usually be put to work for
a temporary job.
Finally, you can take working parts of zero-page and copy them to some
other parts of memory. You can use these locations, carefully putting back
the original contents before returning to BASIC. Don't try this with any
values that are used by the interrupt routines (involved with screen, key-
board, or RS-232); the interrupt can and does strike while your machine
language program is running. And if the interrupt program changes these
zero-page values, your program is going to behave badly.
Project: Screen Manipulation
This project is intended to show how indirect, indexed addressing can be
used effectively. We'll change something on the screen — enough so that
we reach more than 25 1 addresses. Ordinary indexing, therefore, won't
do.
ADDRESS MODES
85
We'll select a number of lines on the screen; within each line, we'll change
a certain group of characters. In other words, we will write the code so as
to manipulate a window on the screen.
To do this, we'll need to code two steps: setting up the start of a screen
line, and later moving on to the next line when needed. Within each line,
we'll work our way through the range of screen columns that we have
selected. In fact, it's a big loop (for the lines) containing a small loop (for
the columns within that line). We'll use indirect addressing to point to the
start of each line, and indexing (the Y register) to select the portion of that
line to change.
Since there's a variety of Commodore machines, we have some problems
to resolve. Except for the C 128 in 80-column screen mode, all Commodore
screens are "memory mapped," that is, the information appearing on the
screen is copied directly from some part of memory. We may change the
screen by changing the appropriate memory. But different machines use
different memory addresses; and in VIC and Commodore 64, the screen
may be moved around. Another thing to consider is that the length of line
varies between different machines— it might be EE or 4 □ or flD columns.
C128 note: Remember to checi< Appendix E, Exercises forttie Commo-
dore 128, for the appropriate coding.
No problem. If you have a 40-column machine, AQ equals $Efl; code
A 0330 LDfl #$Efl
For a 22-coiumn machine, change the above to LDA #$lt; and for an
80-column PET, code LDfi #$5D.
Have you coded the correct value? Let's proceed with our next decision.
In the PET/CBM, screen memory starts at address IflDDO; in VIC or
Commodore 64, the screen starts at whatever page is designated in ad-
dress $DEflfl. Let's code as follows:
PET/CBM: R 033E LDX #$flD
A Q3AD NOP
VIC/Commodore 64: aD33ELDX$DEafl
The NOP instruction does nothing, but it makes the coding the same length
so that we may continue with address $D3A1 in either case. The ft
register tells us our line length, and the X register tells us the page number
on which the screen starts. Let's put them away. The line length will be
86
MACHINE LANGUAGE FOR COMMODORE MACHINES
needed for addition later, so we may put it anywhere safe; the screen
address will be part of an indirect address, so it must go into zero-page.
It's hard to find a zero-page address that may be used in all Commodore
machines; we'll choose $OQBB and $DOBC. $BB contains the low byte
of the address, of course. Let's code
a D3A1 STa $o3ao
a U3AA STX $BC
Note that we are using the zero-page addressing mode for the instruction
at address $03^4. That puts the high byte of the address in place. Now
we'll set the low byte to zero:
a Q3Ah LDa #$□□
a U3A& STa $BB
Our indirect address is now pointing at the start of screen memory. Let's
discuss in more detail what we want to do with the screen. Specifically,
we want to change a number of lines, let's say lA, on the screen. We
will step along our indirect address by adding to the indirect address:
maybe E2, maybe AU, maybe fiD; whatever is in address $D3aD. And
we won't do the whole line; we'll start in column 5 and go to column Ifl.
Let's count the lines in the X register; we'll start X at zero
a Q3AA LDX #$0Q
Now we're ready to do a screen line. Later, we'll adjust the indirect address
and come back here to do another line. We should make a note to our-
selves: "Come back to $ 0340 for the next screen line."
The indirect address is pointing at the start of the line. We want to start
work in column 5. That means that Y should start with an offset of A (the
start of the line plus A). Let's do it:
a03^CLDY#$D4
We're going to walk Y up, and loop back to this point for the next character
on the line. We might note: "Come back to $ 3 <E for the next character."
We're ready to go. Let's dig out the character that's currently on the screen:
a □34E LDa {$BB) ,Y
This is worth a review. Locations $BB and $BC contain the address of
the start of screen memory; on the PET/CBM, for example, this would be
$ a □ □ 0. To this, we add the contents of Y (value A) to create an effective
address of $flDD4; and from location $flQD^ we get the screen char-
acter.
ADDRESS MODES
87
We decide that we will leave spaces alone. The space character shows
on the screen as a value of decimal 32, hex 20. Let's skip the next
operation if it's a space:
a D3SD CMP #$ED
a Q3SE BEQ $035fc
We have to guess at the address to which we will skip ahead, since we
haven't gotten there yet. Make a note: "This address may need correction."
a 035^ EOR #$flG
This is where we manipulate the character. The EOR is a "flip-over"
command; we're flipping the high bit of the screen value. You may look
up screen codes to see what this does, or you may wait and see what
happens. At this point, our code from $0352 joins up. As it happens, we
were lucky again: the address is exactly right to rejoin at $035 1. But if
it were not, you know how to fix it, don't you? Exit the assembler, then go
back and type over.
Now we put the modified character back to the screen:
a D35t STa ($BB) ,y
We have done one character. Let's move along the line to the next char-
acter, and if we have passed column Ifl (Y = 17) we should quit and go
to the next line.
a D35fl INY
a D35H CPY#$1E
a 035B BCC $034E
Y moves along to the next character position: five, then six the next time
around, and so on. So Ibng as Y is less than Ifl (hex 12) we'll go back,
since BCC means "branch less than." If we get past this point, we have
completed the line and must move to the next one.
We move to the next line by adding to the indirect address. We must add
22, or ^0, or flO; the value is in address $Q3ao (you may remember
that we stored it with the instruction at $0341). We must remember to
clear the carry flag before starting the addition, and to add starting at the
low byte of the address (at $BB).
a D35D CLC
a D35E LDA $BB
a 03^0 aDC $D3ao
88
MACHINE LANGUAGE FOR COMMODORE MACHINES
A Q3L3 STA $BB
A DBtS LDA $BC
A DBt? ADC#$DD
A DBtq STA $BC
The last three instructions seem odd. Why would we add zero to the
contents of $BC? Surely that changes nothing. The answer is obvious
after a little thought: there might be a carry from the previous addition.
Now we're ready to count the lines: we had decided to use X as a counter.
Let's add one to X, and test to see whether we have done the lA lines:
A 03tB INX
A QBbC CPX #$nE
A 03tE BNE $D3AC
If we've done the required number of lines, we have nothing more to do
other than return to BASIC:
A DBTD RTS
Disassemble and check It. Again, you'll find that the code occupies more
than one full screen. Return to BASIC.
This time, we'll write a small BASIC program to exercise the machine
language code. Type NEW to clear out any old BASIC code, and enter
lOD FOR J =1 to ID
IID SYS flEfl
lEU FOE K = 1 to 2DD
13D NEXT K, J
The extra loop is to slow things down. Machine language runs so fast that
the effect might not be properly visible if run at full speed.
Project for enthusiasts: Can you change the program to do a different
set of columns? Could you change it so that it affected only the letter " S "
wherever it appeared on the screen?
Comment for VIC-20 and
Commodore 64
This exercise will work as intended. Other types of screen work might call
for you to set the color nybble memory values before you can successfully
work directly with screen memory. The rules for machine language are no
different from those for BASIC: if you wish to POKE to the screen, you
may need to take the color nybble area into account.
ADDRESS MODES
89
Things You Have Learned
—Three address modes are not addresses at all. Implied addressing means
no address at all; accumulator addressing uses the A register and means
the same thing; and immediate addressing uses a value, not an address.
— Absolute addresses reference one location only, somewhere in memory.
Zero-page addresses reference a single address in the range $ODOD to
$□ OFF— the high byte of the address (□□) is the memory page. These
address modes are used for fixed locations containing worl< values or system
interfaces.
—Absolute, indexed and zero-page, indexed allows the named address to be
adjusted by the contents of an index register— X or Y. These instructions can
reach a range of up to 55 1 addresses. They are commonly used for tables
of data or temporary storage areas.
—Relative addresses are used exclusively with branch instructions. They have
a limited "reach" of about IE? locations fonward or backward. It takes a little
arithmetic to calculate the proper values, but the computer usually works this
out for us.
—Indirect addressing is used only for jumps, most often to allow a fixed ROM
program to take a variable jump. The average machine language programmer
will seldom need these, but the principle of indirect addressing is worth learning.
—Indirect, indexed addressing is the most important way to deal with data
anywhere in memory. We may reach anywhere by setting the indirect address,
then we may "fine adjust" that address by indexing it with the contents of Y.
—Indirect, indexed addressing requires the indirect address to be in zero-page.
We need to conserve zero-page locations for this use.
— An addressing mode called indexed, indirect is rarely used when program-
ming Commodore computers, but it's there if you want it.
Questions and Projects
Write a program to clear the screen of your computer— check Appendix
C for the location of screen memory if you've forgotten. Don't just print
the clear screen character ($R3); do it another way. Can you write the
entire program without using indirect, indexed addressing?
Write the program again using indirect, indexed addressing. The program
may be a little shorter. Can you think of any other advantages of writing
this way?
A user wishes to type in a line of text on the keyboard, ending with a RE T U R N.
He then wants to have the program repeat the line ten times on the screen.
What addressing mode or modes would you use to handle the user's text?
Why? You may try your hand at writing the program if you wish.
Take one of the previous exercises and try to write it again without using
immediate addressing. Is it hard to do? Can you see any reason to want
to code without using immediate addressing at all?
6
Linking
BASIC and
Macliine
Language
This chapter discusses:
• Where to put a machine language program
• BASIC memory layout
• Loading and the SO V pointer
• BASIC variables: fixed, floating and string
• Exchanging data with BASIC
91
92
MACHINE LANGUAGE FOR COMMODORE MACHINES
Siting the Program
Up to this point, we liave been placing all programs in the cassette buffer.
This is a good place for short test programs, but we need to examine
alternatives that are often more attractive.
BASIC Memory Layout
C128 and B-128 note: These two machines keep variables in a separate
memory bank from that in which the BASIC program is held. Some of the
considerations described below— especially regarding dangers with the
Start-of- Variables pointer— don't apply. For 0128 details, check Appendix
E, under Exercises for the Commodore 128.
BASIC RRM is organized according to the diagram below. The following
locations are of particular interest:
1 . Below the BASIC area, we have the cassette buffer area. This is available
to us, providing we are not engaged in input/output activity.
2. Start-of-BASIC (SOB) is usually a fixed address within the machine. In PET/
CBM, It's at lO^ai (decimal IDES). In Commodore 64, It's at SDflDl
(decimal In the PLUS/4 series, It's at $10D1 (decimal AO^?). In
the VlC-20, it may be at one of several places: $D^01, or $1ED1.
A pointer marks this location. The pointer is located at $Sfl/$ER (decimal
AQ and Al) in PET/CBIVI, and at $EB/$SC (decimal A3 and AA), In VIC-
20, Commodore 64, and PLUS/4.
You should inspect the pointer and confirm that It contains an appropriate
address. You may notice that it's much easier to do this using the machine
language monitor, since the address Is split between the two bytes (low order
first, as always).
3. End-of-BASIC Is signaled by three zero bytes somewhere after the SOB. If
you command NEW in BASIC, you'll find the three bytes right at the start of
BASIC; there Is no program, so start and end are together. There Is no
pointer that Indicates end-of-BASIC, just the three zeros; but the next location
(SOV) will often be directly behind the end-of-BASIC
BASIC RAM
f
CASSETTE
BUFFER
BASIC
PROGRAM
BASIC
VARIABLES
BASIC
ARRAYS
FREE
DYNAMIC
STRINGS
SOB SOV SOA EOA BOS TOM
Figure 6.1
LINKING BASIC AND MACHINE LANGUAGE
93
The BASIC program that you type in will occupy memory space from start-
of-BASIC to end-of-BASIC. If you add lines to a program, end-of-BASIC will
move up as extra memory IS taken up by your programs. If you delete lines,
end-of-BASIC will move down.
4. Start-of-variables (SO V) is often positioned directly behind the end-of-BASIC.
When the BASIC program runs, the variables will be written into memory
starting at this point; each variable is exactly seven bytes long. A pointer
marks this location. The pointer is located at $EA/$EB (decimal <2 and
A3) in PET/CBM, and at $ED/$aE (decimal AS and <t) in VIC-20, Com-
modore 64, and PLUS/4.
The SOV pointer is extremely important during BASIC load and save activ-
ities. If we give the BASIC command SAVE in direct mode, the computer
will automatically save all memory from SOB to just before the SOV. Thus,
it saves the whole BASIC program, including the end-of-BASIC marker of
three zero bytes, but does not save any variables. If we give the BASIC
command LOAD in direct mode, the computer will automatically load the
program, and thfen place the SOV pointer to just behind the last byte loaded.
In this way, variables will never be stored over the BASIC program; they will
be written above the end-of-BASIC. More on this later.
If the BASIC program is changed, the SO V may move up or down as needed.
5. Start-of-arrays (SO A) also represents one location beyond the end-of-BASIC
variables, and thus could be named end-of-variables. Arrays created by the
BASIC program, either by use of a D I M statement or by default dimensioning,
will occupy memory starting at this point. A pointer marks this location. The
pointer is located at $2C/$BD (decimal AA and -^5) in PET/CBM, and at
$BF/$3D (decimal and A&) in VIC-20, Commodore 64, and PLUS/4.
If the BASIC program is changed, the SOA pointer is set to match the SOV.
Thus, all BASIC variables are wiped out the moment a change is made to
the program.
6. End-of-arrays (EOA) is set one location beyond the last array location in
BASIC. Above this point is seemingly "free" memory — but it's not really free,
as we'll see soon. A pointer marks this location. The pointer is located at
$EE/$EF (decimal and A7) in PET/CBM, and at $31/$35 (decimal
4 q and 50) in VIC-20, Commodore 64, and PLUS/4.
If the BASIC program is changed, the EOA pointer is set to match the SOA
and SOV . Thus, all BASIC arrays are wiped out the moment a change is
made to the BASIC program.
Let's change direction and start to work our way down from the top of BASIC
memory.
7. Top-of-memory (TOM ) is set one location beyond the last byte available to
BASIC. On the PET/CBM and VIC-20, its location depends on the amount
of memory fitted; a 32K PET would locate TOM at $flDDD. On the Com-
94
MACHINE LANGUAGE FOR COMMODORE MACHINES
modore 64, the TOM will normally be located at SAQDD. A pointer marks
this location. The pointer is located at SB-^/SBS (decimal 52 and
53) in PET/CBM, and at $37/$3fl (decimal 55 and 5E.) in VIC-20, Com-
modore 64, and PLUS/4.
If you examine the TOM pointer, you may find that it does not point at the
expected position. That may be because of the machine language monitor,
which has taken up residence at the top of memory and stolen away some
memory.
8. Bottom-of-strings, (BOS) is set to the last "dynamic" string that has been
created. If there are no BASIC strings, the BOS will be set to the same
address as TOM. As new dynamic strings are created, this pointer moves
down from the top-of-memory towards the EOR address. A pointer marks
this location. The pointer is located at $3D/$31 (decimal 4fl and 4R) in
PET/CBM, and at $3 3/$ 34 (decimal 51 and 52) in VIC-20, Commodore
64, and PLUS/4.
A dynamic string is one that cannot be used directly from the program
where it is defined; you might like to think of it as a manufactured string.
If, within a BASIC program, I type: !□□ X$ = "HftPPY NEW YERR",
the BASIC Interpreter will not need to store the string in upper memory;
it will use the string directly from where it lies within the program. On the
other hand, if I define strings with commands such as R$ = R$ + or
INPUT N$, the strings must be built into some spare part of memory.
That's where the BOS pointer comes in: the computed string is placed
high In memory, and the BOS moved down to mark the next free place.
If the BASIC program is changed, the BOS pointer is set to match the
TOM. Thus, all strings are wiped out the moment a change is made to
the BASIC program.
Free Memory: The Dangerous Place
It seems to beginners that there is a great deal of free memory available
above the end-of-arrays and below the bottom-of-strings, and that this
would be an ideal place to put a machine language program. This is a
pitfall: it usually won't work.
Here's the danger. As more and more dynamic strings are created, the
bottom-of-strings location keeps moving down. Even when strings are no
longer needed, they are abandoned and left dead in memory, taking up
space.
The BOS keeps moving down. Only when it touches the EOfi will the
dead strings be cleaned up and the good ones repacked, an action called
garbage collection. It's Important for BASIC programmers to know about
LINKING BASIC AND MACHINE LANGUAGE
95
garbage collection: except on BASIC 4.0 and Commodore PLUS/4 sys-
tems, it can be a cause of serious program slowdown.
It's evident that the space between EOfi and BOS is not safe. If you put
a program there, the strings will eventually destroy it. We must look else-
where.
Where to Put Your ML Program
First, you may put your program in the cassette buffer. Providing you are
not performing input/output activity, your program will be safe. Your space
here is limited to IRQ characters or so.
SOB sov SOA EOA BOS TOM
CASSETTE
BASIC ...
VAR
ARR
STR
Figure 6.2
Second, move down the top-of-memory pointer and place the program in
the space that has been freed. Your spdbe here is unlimited. Programs
placed here will take up permanent residence until the power is turned
off. Many monitors, such as Supermen, live here.
SOB
sov
SOA
EOA BOS
NEW OLD
TOMTOM
C.B.
Figure 6.3
SOB
OLD NEW SOA
SOV SOV I
EOA BOS TOM
C.B.
Figure 6.4
Third, move up the start-of-variables pointer, and place the program after
the end of BASIC and before the new start-of-variables. Your space here
96
MACHINE LANGUAGE FOR COMMODORE MACHINES
is unlimited. Programs placed here will tend to "join company" with the
BASIC program; the two will save and load together.
After moving a pointer— as was done in the last two methods — it's a good
idea to return to BASIC and command CLR, so that all other variable
pointers will align correctly with the ones that have moved.
These three areas will be discussed more in a few moments. First, there
are one or two extra locations available to VIC-20 and Commodore 64.
Extras for VIC and Commodore 64
The Commodore 64 has a free block of RAM at locations SCDOD to
$CFFF (decimal ^RIBE to S3EA7). That's 4Kof RAM not being used;
you may write your programs there. Before you do so, check to make sure
that the memory is not being used by any other programs. It's a popular
place in the Commodore 64, and many utilities and commercial programs
zero in on this available memory.
If you intend to write programs entirely in machine language, with no BASIC
content at all, you may completely remove BASIC from the Commodore
64 system and claim the space as available RAM. This gives you the
whole block from $ fl □ 1 up to $ CFFF for programs and data — a whop-
ping 50K— and even more could be liberated if necessary. BASIC may
be made to disappear from the Commodore 64 with the equivalent of
POKE IfSA (LDA #$3t, STA $□!). It may be reinstated with the
equivalent of POKE 1 , 55 (LDA #$37 , STA$D1). Be very careful.
With BASIC gone, the computer doesn't even know how to say READY.
On all Commodore machines it's possible to move up the start-of-BASIC
pointer and use the space freed below. To do so, it's essential to store a
value of zero into the location immediately before the new start-of-BASIC,
and to align all other pointers, usually by going to BASIC and commanding
NEW.
This works, and will make as much space available as is needed. BASIC
programs will relocate as they load. But since the computer needs to be
reconfigured before the main program is loaded, and often needs to be
restored to its original configuration after the program is run, the method
is not popular in most Commodore machines. It's used fairly often in the
VIC-20, however.
The video chip in the VIC-20 can "see" RAM memory only in the memory
space $□□□□ to $1FFF (decimal to fllH). Whatever variable in-
formation appears on the screen must be taken from this memory area.
LINKING BASIC AND MACHINE LANGUAGE
97
The VIC-20 can also get information from $aDDD to SRFFF, but there's
no RAM there; we can't manipulate this memory area.
If we want to perform special visual effects on the VIC-20, we must ma-
nipulate data in the area $Daaato$lFFF. Let's look at what is available.
$DOOD to $D3FF is used by the "system;" other than the cassette
buffer, we must leave it alone. $D^DD to $DFFF contains no memory
unless a 3K BAM expansion is added. $!□□□ to $1DFF contains the
BASIC program, and $ IE DO to $1FFF is screen memory. Details may
vary, but the answer always comes out the same: there's no space to do
our video effects.
A popular VIC-20 solution, especially where 8K or more of RAM expansion
has been added, is to increase the start-of-BASIC pointer, thus liberating
space in low memory. This may now be used for visual effects and for
machine language programming, too, if any space is left over. In the VIC-
20, this approach is necessary, but it's still a bit clumsy.
The start-of-variables pointer can be the cause of many troubles, if it's not
understood. The rules covering it are as follows:
1 . Variables are written starting at the SO V.
2. BASIC S A VEs will save from memory beginning at start-of-BASIC and stop-
ping at SOV.
3. Direct command BASIC LOADs will bring a program into memory, relocating
if appropriate, and then set the SO V pointer to the location following the last
byte loaded.
4. Changes to BASIC programs cause memory to be moved — up or down —
starting from the point where the change Is mads and stopping at the SOV.
The SOV will then be moved the appropriate distance up or down.
These seem to be innocent rules. Rule 1 defines the purpose of the SOV.
Rule 2 shows how the SOV controls the SAVE command so that the
entire BASIC program is saved, but not the variables. Rule 3 arranges
that short programs will have a large amount of variable space available;
long ones will have less. Rule 4 ensures that a BASIC change makes
extra room in memory or reclaims memory space.
But if the SOV gets the wrong address, we're in trouble. The rules work
against us. Variables may be written into disastrous places. SAVEs will
cause too much or too little to be saved. LOADs may fix things, since
SOV will be changed by the load action. An attempt to change a program
with a bad SOV may cause too little or far too much memory to be moved
around. We must get the SOV right.
98
MACHINE LANGUAGE FOR COMMODORE MACHINES
How can the SO V go bad on us? Let's take three examples, corresponding
to the three major places that we might put machine language programs:
We have a program in the cassette buffer, and a BASIC program that
goes with it. We enter or load the BASIC program (the SOV is all right so
far), and then we LOAD the machine language program; the SOV ends
up disastrously somewhere in the cassette buffer area.
We're in trouble. The program seems to list correctly, but it's sick. If we
BUN, variables will start to be placed in the cassette buffer area; as more
variables are created, they are placed in progressively higher memory
locations. Eventually, the variables start to write over the BASIC program.
Everything stops. The poor programmer says LIST to see what's hap-
pened; his BASIC program is gone, and all that's left is gibberish.
We're in more trouble. Alternatively, the programmer decides to save his
BASIC program and commands SAVE. BASIC starts to save memory
beginning at start-of-BASIC . . . and keeps saving, and saving, and saving.
It won't stop until it reaches the SOV, but that's below where we started.
We won't get there until the address "wraps around" and comes back up
through zero. The poor programmer — if he or she waits long enough —
discovers that the tiny five-line BASIC program has been saved as over
E5D blocks on disk, or fifteen minutes worth of tape. And the saved
program is useless.
We're in still more trouble. Alternatively, the programmer lists the program,
and decides to delete one character from a line of BASIC. BASIC im-
mediately starts to move memory, starting at the change point. It won't
stop moving memory until it reaches SOV, but that, again, is below where
we started. It will move everything that can be moved. RftM will be moved
along, which may not hurt anything; then the I A chips will be moved,
which may scramble colors or make the display go crazy; then it will try
to move ROM, which won't work because ROM can't be changed; then it
will wrap around to zero-page and move everything there, which is fatal
to the system. Eventually, it will collapse before reaching SOV since it
destroys its own working pointers.
All this could have been avoided if the programmer had loaded the machine
language program first, and then loaded the BASIC program. The SOV
would be placed behind the BASIC program, which is where it belongs in
this case.
Quiet Interlude
It's easy to see how the problem occurs, once you understand about the
SOV and its role. But if you don't understand the SOV, the results can
UNKING BASIC AND MACHINE LANGUAGE
99
shake your self-confidence. Many programmers have given up on machine
language because of a bad experience with SOV .
It works this way. The student writes a perfect program into the cassette
buffer and saves it using the machine language monitor. Later, with a
BASIC program in place, the student recalls the program and inadvertently
moves SOV to an impossible location. When BASIC runs, the variables
will start to be written behind the machine language program, ahead of
the BASIC program. As more and more variables come into play, they
creep relentlessly toward the BASIC coding.
Our eager student— with a perfect machine language program and a per-
fect BASIC program— now decides to say RUN. The BASIC program runs
for a while, and then grinds to a halt, usually with a crazy screen or reporting
an error in a nonexistent line. We know what's happened, of course: the
variables have started to write over the BASIC program. But our unfor-
tunate student doesn't know that. The command LIST is entered, and
out comes nonsense.
What goes through the programmer's mind at this time? "I was so sure
that the program is correct [in fact, it is]; but it's so bad that it's destroyed
memory! I suppose that machine language is much more difficult than I
thought."
And the student loses hope and gives up, not knowing that there's only
one small piece of information needed to fix everything up. This is only
one of the things that might go wrong when the SOV pointer is improperly
placed; even an attempt to change or save a BASIC program can cause
system failure.
Such experiences destroy confidence. They are responsible for the myth
that machine language is hard and only super-clever programmers can
cope with it.
The Machine Language Monitor SAVE
Now that we're becoming aware of the SOV pitfall, we're ready to discuss
how to save a program in machine language. You probably understand
why I've been delaying this command until this time. The MLM save com-
mand typically goes
S "PROGRAM", 01, DaacDati
This would be the tape format. The command is S and is followed by
the program name. The device is tape, so we type Dl — be sure to give
two digits. Next comes the beginning address (in the example $D33C)
100
MACHINE LANGUAGE FOR COMMODORE MACHINES
followed by the end address plus one. In the example, the last location
saved will be $D3tO. For disk saves, we might want to add the drive
number:
S "0:PROGRaM", Dfl, 0330, 03bl
These programs, once saved, may be loaded directly from BASIC, but
watch the SOV carefully. VIC-20 and Commodore 64 BASIC LORD com-
mands should contain the extra field to defeat relocation: LORD "PRO-
GRRM " , a / 1 will insist that the program load back into the same memory
locations from which it was saved.
More on LOAD
There is a machine language L command to do a program load without
changing any pointer (especially SOV). There are a number of different
machine language monitors around, and the L command does not work
the same way on all of them. You might check out the one you are using:
ideally, the L command (format: L "PROGRfiM", Dl) should bring back
the program without relocation.
The L command is of limited value. A program user often cannot be
expected to load up a machine language monitor and use it to go through
a L load sequence. The program should take care of things for the user.
We have been careful to say that the BASIC LORD command changes
the SOV when given as a direct command. If a LORD command is given
from within a program, SOV is not changed; but there's a new item to be
taken care of.
Programmed LORD has been carefully designed to perform a function
called "chaining." That's a BASIC technique, and not within the scope of
this book. Chaining, however, has two important characteristics:
1 . No pointers are affected. The program will not lose any variables when it
performs a LORD. That's good: we will not lose any of our computations.
2. Once a LORD is complete, the BASIC program will resume execution at the
first statemerit. It will not continue from where It left off; It will go back to the
beginning. For our application, that's bad; we seem to have lost our place
in BASIC.
If we understand the problem that item 2 creates, we can easily fix it by
using item 1. Here's an example to illustrate the problem: we have a
program on disk written for the cassette buffer called " ML " , and we want
to have a BASIC program bring it in. We could code as a first line: !□□
LORD " ML " , fi — but we'd have a problem. First, the program would load
LINKING BASIC AND MACHINE LANGUAGE
101
ML. Then it would go back to the beginning and load ML. Then it would
go back to the beginning . . . and so on. This is not satisfactory. Let's use
rule 1 to fix everything:
!□□ IF A = l GOTO 13D
IID a = i
150 LOAD "ML",fl,l
13D . . . continues
When we say RUN, the first line is executed, ft is not equal to one, so
we continue on line IID . ft is set to one, and line lED causes a load
of the desired program. BASIC goes back to the beginning, but all variables
are preserved, so ft is still equal to 1. Line IDD tests ft and goes to line
1 3D, the next statement beyond the load. Everything works as required.
If there are multiple LOftDs, line lUD might be changed to ID □ ON ft
GOTO 130, 15D,17D . . . as necessary.
Caution: we are discussing the programmed LOfiD command only in the
context of loading machine language modules. If you want to have a
program load in another BASIC program (chaining or loading) the above
rules still apply but may need to be used differently.
Other SOY Blunders
We have discussed the horrible results of loading a machine language
program into the cassette buffer (using a direct command) after BASIC
has been loaded. By now, we should have learned to avoid making this
mistake. What about programs stored in other areas, such as high memory
or after BASIC?
Suppose we want to place a program into high memory, either by moving
the top-of-memory pointer down to make room, or by using the spare RftM
at $CDDD to $CFFF of the Commodore 64. We also have a BASIC
program to load. Will loading in the wrong order harm SOV?
The answer is yes, although the problem is not so severe. You can see
that after loading a program to high memory using a direct command,
SOV will be positioned immediately above it. But that's too high — there's
no room for variables and we'll get an OUT OF MEMORY error for almost
anything we do.
Obviously, we can't leave SOV in the upper stratosphere. We must load
the high memory first, and then the BASIC program. The second load will
straighten out the SOV pointer. If you try this, you'll find that it is necessary
to fix up the top-of-memory pointer and command NEW between the two
102
MACHINE LANGUAGE FOR COMMODORE MACHINES
loads; you cannot even give the next LORD command if you're apparently
totally out of memory.
Review: Fixing Pointers
if in doubt, examine the pointers by displaying them with a M command.
For VIC/64/PLUS/4, the command would be M QDEB QQ3A; with
PET/CBIVI, use M DOSfl 0D37; in either case, be sure that the start-
of-variables pointer is set to a "sound" value.
As always, you can change an incorrect memory value — in this case, an
incorrect vector— by moving the cursor back, typing over the values to be
changed, and pressing RETURN.
After End-of-BASIC— Harmony
Suppose we place the machine language program behind the end-of-
BASIC— that's the three zeros in memory— and move up the SOV so that
variables won't disturb this program. How will everything work now?
Things will work very well indeed. This time, we need to load our BASIC
program first; the SOV will go immediately behind BASIC. Then we may
load our machine language program, and the SOV moves right behind it.
The SOV is in exactly the right place, assuming we load in the right order.
(If we don't, the variables will destroy our machine language program.)
Once our two programs are together, and we say S R VE , the combination
program— BASIC and machine language together— will be saved. A little
thought will reveal that memory from start-of-BASIC to just before start-
of-variables contains everything we need. A subsequent load will bring
everything back in, and position SOV to exactly the right place. We now
have a "unit" program— BASIC and machine language working together,
loading and saving as one program.
There's one small problem in this arrangement. Once we have married
the BASIC and machine language programs, we must not change the
BASIC program. If we added to or subtracted from this program, the
machine language program would move up or down — the relocation of
memory goes right up to SOV. The program might not be able to work in
the new place, and, of course, our SYS commands would be wrong.
BASIC Variables
There are four types of entry in the BASIC variable table. All variables,
regardless of type, occupy seven bytes; the first two bytes are the name.
LINKING BASIC AND MACHINE LANGUAGE
103
and the remaining five bytes (not always fully used) contain tlie value or
definition. The variable type is signaled as part of the name: high bits are
set over one or both letters of the name to signal a specific type.
SOV
L
SOA
L
EACH VARIABLE IS EXACTLY 7 BYTES LONG.
VARIABLES APPEAR IN THE ORDER IN
WHICH THEY ARE USED.
Figure 6.5
For example, if a floating point variable had a name fiB, the name would
be stored in the two bytes as $-^1 , $^E— the ASCII codes for fi and B.
The same would be true if the variable were named ABACUS, since only
the first two letters of the name are kept. In contrast, if the variable were
named AB%, meaning that it was an integer variable, the name would be
stored as $C1 , $C2. The ASCII codes are the same, but the high bit
has been set over them. To complete the picture, a string variable named
aB$ would be coded with the name $A1, $CE — the high bit is set over
the second character only.
r
HIGH BIT SET FOR INTEGER VARIABLES AND FUNCTIONS
HIGH BIT SET FOR INTEGER AND STRING VARIABLES
NAME
VALUE
2 BYTES
1
5 BYTES
1 1 1 1
Figure 6.6
There's a fourth type of entry that can go into the variable table, but it's
not a variable: it's a function definition. If we give the variable command
DEF FN A ( ... an entry will be made in this table. It will be distinguished
by the high bit being set over the first character only.
String variables use only three of the five bytes provided; the first byte
signals the length of the string, and the next two bytes give the string's
address. This group of three bytes is called a descriptor.
704 MACHINE LANGUAGE FOR COMMODORE MACHINES
There are two types of numeric variables: floating point and integer. Float-
ing point variables use all five bytes; integer variables use the first two
bytes only. It's possible to extract the value from a floating point variable
and put it to work, but it's not a simple procedure. A description of how
to do this is given in Appendix F. In contrast, it's quite easy to take the
value from an integer variable and use it.
Let's try an example. Type NEW, followed by A = 5 = : = 5. This cre-
ates two different variables: ft and B%. Now go to the machine language
monitor. The variables should be near the start-of-BASIC, but if you wish
you can find their exact address by examining the SOV pointer ($2 a/
$2B on PET/CBM, or $ED/$EE on VIC, Commodore 64 or PLUS/4). On
the Commodore 64, we might find that the variables start at $0flD3; to
display both of them, we type M DflOB OfllD. We see the floating
point variable, R:
Al DO fl3 ED □□ OQ □□
The first two bytes are the name— $^1 is ASCII for ft, and the zero
signifies no second letter— but Where's the 5? Embedded within the fl3
ED □□ DO □□, that's where; and it's a good deal of work to extract the
5 for further processing.
Behind this variable, we see the integer variable, B:
CE flD □□ ns □□ DO DD
Hex CE is the ASCII for the letter B ( $^E ) with the high bit set. $flD is
zero with the high bit set — again, there's no second letter. The value is
in the next two bytes, and it's easy to read. The last three bytes are not
used.
Which is easier for machine language to interface with? Obviously, the
integer variable. It's often quite suitable for the program work at hand:
counting characters, setting pointers, and similar tasks.
Exchanging Data: BASIC and Machine
Language
If BASIC and machine language wish to pass data back and forth, there
are several approaches. Perhaps the simplest is to have BASIC POKE
the values into a given location, and machine language load them as
needed; in the opposite direction, machine language will store the values
and BASIC will PEEK them.
Another method is more sophisticated. BASIC variables are stored in
LINKING BASIC AND MACHINE LANGUAGE
105
memory: why can't a machine language program go after the variables
exactly where they lie and extract their value or change them? It sounds
like a good idea.
By now, we know how to ask machine language to search for a specific
BASIC variable. Given the name, we can get the address of the first
variable from the SOV pointer and store it as an indirect address. Using
Indirect, indexed addressing and stepping the Y register from □ to 1 we
can see if the name matches. If not, we add seven to the indirect address
to take us to the next variable. If It does match, our indirect address is set
up at the start of the variable; we can set Y to E , 3 , A , 5 , and t and
extract the whole value. If the variable is type Integer, we need only extract
the first two bytes (Y = 5 and 3). If the variable is not in the variable table,
we'll step our Indirect address until It matches the start-of-arrays; at that
point, we know that we have missed the variable.
For a small number of variables, there's a short cut. Variables are placed
into the variable table in the order in which they are defined: whichever
variable Is defined first in the BASIC program will be first in the variable
table. So if we arrange for our variables to be defined in a certain order,
we can streamline our machine language search to "first variable," "sec-
ond variable," and so on, with no need to examine the names.
Let's take this one step further. If we want to use the first variable, all we
need to have Is the address of the first variable somewhere in zero-page
so that we may use It as an indirect address. We already have that ad-
dress—it's the SOV, the start-of-variables, and it's there pointing helpfully
at the first variable for us. By increasing the value of Y appropriately, we
can reach beyond the first variable and Into the second or, for that matter,
the third or the thirty-sixth.
Project: We plan to place the machine language program behind the end-
of-BASIC. This will vary, depending on the machine being used. The
following code shows the correct addresses for the Commodore 64. Refer
to Appendix E for other machines.
CI 28 note: Remember to check Appendix E, under Exercises for the
Commodore 128, for the appropriate coding. There's a lot here on how
to dig out information from another memory bank.
First, let's do our BASIC coding to estimate Its size. We need to guess at
the location of the end-of-BASIC so as to place our machine language
program. This program will ask machine language to take a value, V%,
and multiply it by ten. Remember to say NEW. We write the BASIC program
as follows:
106 MACHINE LANGUAGE FOR COMMODORE MACHINES
110 FOR J = l TO 5
lED INPUT "VALUE"
13D SYS + + + +
140 PRINT "TIMES TEN = " ;
150 NEXT J
It seems likely that our BASIC program will occupy less than IE? bytes.
We may check this later, but it seems safe to plan to start our machine
language program at around EO-^R + lET.orElTt (hexadecimal fl fl 0).
On that basis, we may change line 130 to SYS E 17 1. Do nof try to run
the program yet.
At this point, we could save the BASIC program to tape or disk and develop
the machine language program. This would allow us to refine each of the
two parts independently. For the sake of brevity — and because our ex-
ample is an easy one and won't need touching up — we'll write the machine
code directly into memory.
Switch into the machine language monitor. Assemble the following code:
A
OfiflO
LDY
#$DE
A
OflflE
LDA
($ED) ,
Y
A
D&&A
STA
$033C
A
Oflfl?
STA
$033E
A
OflfiA
LDY
#$D3
A
OflflC
LDA
($ED),
Y
A
OflflE
STA
$033D
A
Oflqi
STA
$033F
We have now extracted two bytes from the first variable, V%. The high
byte has been stored at both $033C and $033E; we'll see why in a
moment. The low byte of the value has gone to $03 3D and $033F.
Project for enthusiasts: You might be able to code the above more com-
pactly by more effective use of indexing.
A
ASL
$033D
A
oaq?
ROL
$033C
A
DflRA
ASL
$033D
A
oflqD
ROL
$D33C
We have multiplied the contents of $D33D/$033C by two, and then we
have multiplied it by two again. These locations now contain the original
value times four. Note that we ASL the low byte and then ROL the high
LINKING BASIC AND MACHINE LANGUAGE
107
byte. Perhaps we should be checking for overflow; but let's trust the num-
ber to be within range for now.
Since we have the original number times four in $ □ 3 3 D/$ 3 3 C, we can
add it to the original number in $ 3 3 F/$ □ 3 3 E to get the original number
times five:
A
OflAD
CLC
A
□ flAl
LDA
$D33D
A
□ flA^
ADC
$D33F
A
□ flA7
STA
$□330
A
□ AAA
LDA
$033C
A
OflAD
ADC
$D33E
A
□ flBD
STA
$D33C
Now locations $D33C/$D33D contain the original number times five. If
we double the number one last time, we'll have the value times ten:
A 0&B3 ASL $033D
A DflBt ROL $033C
We have multiplied the number by ten. Now let's put it back into the var^ble
A
OflBq
LDY
#$0E
A
OflBB
LDA
$D33C
A
□ ABE
STA
($ED) ,Y
A
□ flCQ
LDY
#$□3
A
DflCS
LDA
$D33D
A
□ flC5
STA
($ED) ,Y
A
□ flC7
RTS
The numbers go back exactly the same way we drew them out. We must
be careful to keep the high and low bytes correct. Integer variables have
the high-order byte first, followed by the low-order byte; this is exactly the
reverse of the way we use 650x addresses.
We must perform one more task before wrapping up the program. We
must change the start-of-variables pointer to a location above the machine
language program. That would be SQflCfi, and so we display the SOV
pointer with M UQEB □ DEE and change the pointer to
:DD2D Cfl Dfl
Check . . . disassemble . . . and then back to BASIC. List, and you'll
see your BASIC program again. There's no sign of the machine language
program, of course, but SAVE will now save everything together.
708
MACHINE LANGUAGE FOR COMMODORE MACHINES
RUN the BASIC program. Enter numbers as requested. Confirm that they
are multiplied by ten.
You may recall that our machine language program does not check for
overflow. RUN the program again, and see if you can find the highest
number that can be multiplied by ten without error. What happens at time
of overflow? Is it what you expected?
Project for enthusiasts: Can you add checks for overflow to the above
program? You must decide what to do if overflow occurs: print a message;
set the value to zero; or whatever you decide. But you shouldn't stop the
program or break to the monitor. Such a thing would upset the program
user. Your program will be longer. Don't forget, therefore, to change the
SOV pointer at $ED/$EE so that your program is safe from variables
—Small machine language programs can be conveniently written and checked
out in the cassette buffer. We have been doing this during the exercises. This
area Is not satisfactory for large programs, or programs we want to save on
tape.
—Programs can take up semi-permanent residence near the top-of-BASIC
memory; the top-of-memory pointer needs to be moved down to protect it.
These programs often need a separate "setup" to place them.
—Programs can be placed behind the end-of-BASIC, which is marked by three
consecutive zero bytes In memory. The start-of-varlables pointer must be
Increased so that variables don't write over the program. Care must be taken
not to change the BASIC program after this Is done.
—The VIC-20 frequently has the start-of-BASIC moved up to make room for
video information in lower memory. As long as we're moving this pointer, we
might move It a little further and make room for some machine code.
—The Commodore 64 has an unused block of RAM at addresses $CDDO to
$CFFF; check to see that no other programs are using this area.
—The start-of-variables pointer is intimately tied In with BASIC'S SAVE and
LOAD commands. It Is extremely Important to ensure that any LOAD se-
quence leaves this pointer in a safe place, so that variables cannot write over
program code and thus cause program destruction.
—Machine language monitor S (save) and L (load) commands can be used
for staging programs in various parts of memory. Again, great care should
be taken to ensure that the pointers are sound after the use of such instruc-
tions.
— A BASIC program may contain LOAD commands that will bring in any of the
following: a different BASIC program, a machine language program, or data.
Again, careful handling is needed.
Learned
LINKING BASIC AND MACHINE LANGUAGE
709
—BASIC variables are of three major types: integer, real (floating point), and
string. I\^achine language programs are capable of reading and using any of
them; in particular, integer variables are quite straightforward.
—If we want, we can simplify the task of searching for BASIC variables by
deliberately creating them in a certain sequence.
Questions and Projects
Write a simple BASIC and machine language program set that allows
BASIC to input a number less than 25 1; POKE it somewhere in memory;
call machine language that will divide the number by two; PEEK it back
and print it.
A program that brings in other programs is called a "boot," or, more
accurately, a bootstrap program. Write a simple BASIC boot program to
bring in a previous program exercise that was located in a cassette buffer
(say, the program from Chapter 2 that printed HELLO), and then call it
with a SYS.
Bootstrap programs are especially popular with VIC, Commodore 64, and
PLUS/4 for bringing in chunks of data such as sprites, new character sets,
or whole display screens of information. You might like to try your hand
at setting up such a system.
Try your hand at this. I have a BASIC program that reads
1D0X = 5
110 SYS ...
lEU PRINT A
Write the machine language to be called by the SYS so that it changes
the name of the variable X to A. Caution: this may be fun, but it's dangerous
in real programs since you may end up with two variables that have the
same name.
This chapter discusses:
• The stack for temporary storage
• USE: an alternative to SYS
• Interrupts: IRQ, NMI, and BRK
• The la chips: PIA and VIA
• Infiltrating BASIC: the wedge
112
MACHINE LANGUAGE FOR COMMODORE MACHINES
A Brief Intermission
If you have been following along and performing the various projects, you
should know a great deal about the principles of machine language. You
should be capable of trying your hand at a number of small projects, and
investigating areas that may be of special interest.
This is a good time to stop and take stock. The remaining chapters are
"icing on the cake" . . . they give extra detail and fine tuning on aspects
of machine language. If you feel uncertain about any material covered so
far, go back. Fix the fundamentals firmly in focus before you proceed and
plunge into ponderous points of interest.
Temporary Storage: Tlie Stacl<
The stack is a convenient place to put temporary information. It works like
a stack of documents: you may drop (or "push") an item onto the stack;
when you take an item back again (or "pull"), you'll get the last one that
you put there. Formally, it's called a last-in, first-out (LIFO) discipline; it's
natural and easy to understand.
The important rule to keep in mind about the stack is: "Leave these prem-
ises as clean as when you found them." In other words, if you push three
items onto the stack, be sure you pull those three items back off again.
Don't ever branch away and leave the stack littered.
The stack is in memory at page 1. The stack pointer (SP) is one of the
items displayed in the register. To look for the information on the stack,
you must add $ □ 1 □ □ to the value to get the next available stack position.
As an example, if the SP shows a value of SFfl, the next item to go on
the stack will go into address $01Ffl; the moment we put an item onto
the stack, the pointer will move down so that it becomes $F7.
As the stack is filled, the stack pointer goes down. As the items are brought
back out of the stack, the stack pointer goes up. A low value in the stack
pointer means a full stack: a value below $A0 signals trouble.
The 650x chip itself doesn't give the stack any special treatment. If a
machine language program— probably because of a coding error— wanted
to push one thousand items onto the stack, that would be OK as far as
the microprocessor was concerned. The stack would never leave page 1 :
as the stack pointer went down beyond zero, it would wrap around to $FF
and keep going. You'd never get those thousand distinct items back, of
course. Similarly, if a program wanted to pull a thousand items from the
STACK, USR, INTERRUPT, AND WEDGE
113
SP
NEXT ITEM
PUSHED WILL GO
TO ADDRESS $01 F8
NEXT ITEM
PULLED WILL COME
FROM ADDRESS $01 F9
Figure 7.1
stack— whether or not they had been put there before— the processor
would happily move the stack pointer round and round page 1 , delivering
bytes. There would only be B5t different values delivered, of course, but
the processor doesn't care.
Within the BASIC environment, the stack pointer starts around $FA (the
first item will go into the stack at address $DlFfi), and goes down from
there. When the stack pointer goes below about $<D, BASIC will signal
OUT OF MEMORY. That's over lt.D available locations on the stack,
plenty of room for most applications
PHA (push A) and PLA (pull A)
How may we use the stack? Suppose we have a value in the ft register
and in a moment we will want to use it. First we need to print something,
and the character to be printed must be loaded into the ft register. How
can we put away the value in ft and bring it back later? We could slip it
into another register with a transfer instruction (TAX or TRY) and bring
it back from there; or, we could store it into memory and load it back.
Alternatively, we could PUSH the ft register (PHft) to the stack and PULL
(PL ft) the value back later.
Again, let's do an example. Suppose the ft register contains 5, and the
USED
Olrr
1 iccr\
UocU
irc
USED
01 FD
USED
01 FC
USED
01FB
USED
01 FA
USED
01F9
FREE
01F8
I I
I I
I I
114
MACHINE LANGUAGE FOR COMMODORE MACHINES
stack pointer is at $F 3. If \he program says P Ha, the value 5 is stored
at address $D1F3, and the stacl< pointer changes to $F2. Later in the
program, we encounter the instruction PLA: the stacl< pointer moves bacl<
to $F3 and the value 5 is read from address $D1F3 and placed into
the A register.
It's a handy way to put away a value in a for a moment.
PHP (push processor status) and PLP
Sometimes when we are writing a program, we want to test for a condition
now but act on the result of that test later. We can arrange to do this by
putting the flags away for the time being, and then bringing them back
when we want to test the flags. We use the instruction PHP (push the
processor status word) to place all the flags on the stack, and PLP (pull
the processor status word) to restore the flags to the status register (SR).
Why would we need to do this? Perhaps an example will illustrate. Suppose
we are reading a file of customer purchases, and as we input a data item,
we discover that this is the last one— it's the end of the file. That means
that we want to close the file and summarize the customer's activity —
though not just yet. First, we must handle the item of information that we
have input. So we can "stack" our end-of-file information, handle the last
record in the same way as previous records, then bring back the status
to see whether it's time to close the file and print the totals. We'll be using
PHP and PLP for exactly this kind of task in the next chapter.
PHA and PHP both put exactly one item onto the stack; PL a and PLP
pull one item. There are other commands that handle more than one stack
location.
JSRanof RTS
We know these commands. What are they doing here?
When a JSR command is executed, the return address is placed onto
the stack. When an RTS command is executed, the return address is
picked from the stack, and that's where the program returns to.
More precisely, when a JSR occurs, the processor places onto the stack
the return address minus one as two bytes; the high-order part of the
address goes to the stack first. When an RTS is encountered, the pro-
cessor takes the two bytes from the stack, adds one, and then proceeds
from the address so formed.
Example: If address $0355 contains the command JSR $Q33C, the
STACK, USR, INTERRUPT, AND WEDGE
115
following events occur. The return address would be $0355, the instruc-
tion directly behind the JSR; but an address of $035^ is calculated —
the 03 goes to the stack first, and the SA below it. The subroutine at
$D33C now starts to run. Eventually, it encounters an RTS. The values
SA and 03 are pulled from the stack and formed into address $Q3SA;
one is added, and the processor resumes execution at address $Q355.
You hardly need to know this. We have been using subroutines for some
time without knowing that all this happened. But sometimes, it's useful to
be able to examine the stack, asking, "Who called this subroutine?" The
answer Is there.
Interrupts and RTI
There are three types of interrupt: IRQ, NMI, and the BRK instruction.
IRQ (interrupt request) and NMI (non-maskable interrupt) are pins on
the 650x. A suitable signal applied to the appropriate pin will cause the
processor to stop what it's doing and run an interrupt routine. The BRK
instruction might be thought of as a fake interrupt— it behaves in a similar
manner to IRQ.
When an interrupt signal occurs, the processor completes the instruction
it is currently working on. Then it takes the PC (the program counter, which
contains the address of the next instruction) and pushes it onto the stack,
high byte first. Finally, it pushes the status register to the stack. That's a
total of three bytes that go to the stack.
The processor then takes its execution address from one of the following
locations:
IRQ or BRK— from $FFFE and $FFFF
NMI —from $FFFR and $FFFB
Whatever value is found in these pointers becomes the Interrupt execution
address: the processor starts to run at this address. Eventually, the pro-
cessor encounters an RTI instruction. The status register and the PC
address are taken from the stack, and the interrupted program resumes
where it left off.
Note that the address on the stack is the return address. This differs from
JSR/RTS, where the return address minus one is stored.
On all Commodore machines, the IRQ strikes about sixty times a second.
The NMI is unused (but available) on PET/CBM; it isn't available in the
116
MACHINE LANGUAGE FOR COMMODORE MACHINES
Plus-4 series; and on VIC-20, Commodore 64, and Commodore 128, it is
used for tlie RESTORE l<ey and for RS-232 communications.
The BRK command can be distinguislied from tfie IRQ signai by means
of a bit in tlie status register. Bit A is the B, or breal< flag; if it's set, the
iast interrupt was caused by a BRK and not by an IRQ.
Later, we wili discuss using the interrupt routines for our own programming.
By the time we can "catch" the interrupt, several more things will have
been pushed to the stacl<: the a, X, and Y registers. This is done by a
ROM program, not the processor; but it will prove handy since we can use
these registers, safe in the l<nowledge that they will be restored at the end
of the interrupt.
Mixing and Matcliing
The processor uses the stack mechanically. If we know how to manipulate
the stacl<, we can use it for surprising things. For example, an RTS can
be given even though there was no subroutine call; all we have to do is
prepare the stack with the proper address. Try to figure out what the
following code will do:
LDft
PHA
LDfi #$tfl
PHft
RTS
This coding is identical to JMP We have placed a "false return
address" onto the stack, and RTS has removed it and used it. This may
not seem very useful, since we could easily have coded the JMP $B<tH
directly. But look at the following code:
LDa TABLEl, X
PHa
LDA TaBLEB, X
PHa
RTS
The principle of coding is the same, but now we can "fan out" to any of
several different addresses, depending on the value contained in X.
USR: A Brother to SYS
We have used SYS a number of times. It means, "Go to the address
supplied and execute machine code there as a subroutine." U S R is similar
STACK, USR, INTERRUPT, AND WEDGE
117
in many respects: it means, "Go to a fixed address and execute machine
code there as a subroutine." The fixed address may be POKEd into the
USR vector. On most Commodore machines this is at addresses 1 and
E; on the Commodore 64, it's at addresses 7fl5 and 7 fit (hex OB 11
and D315).
There's another difference that seems important at first. SYS is a com-
mand; USR is a function. You cannot type the command USR ( □ ) — ail
you'ii get is SYNTAX ERROR. You must say something iil<e PRINT
USR ( ) or X = USR ( D ) , where USR is used as a function. It seems
as if SYS was meant to connect to action programs, and USR was meant
to link to evaluation programs. In reality, the difference in usage is not that
great.
Whatever value is within the parentheses— the argument of the US R func-
tion — is computed and placed into the floating accumulator before the
USR function is called. The floating accumulator is located at $5E to $b3
in most PET/CBM computers, and at $tl to $tt in VIC-20, Commodore
64, and PLUS/4. Floating-point representation is complex, as we have
hinted in Chapter 6. l\/lost beginning programmers prefer to leave this area
alone and pass values through memory POKEs or integer variables.
When the USR function returns control to BASIC, the function value will
be whatever is in the floating accumulator. If we have not modified it, this
will be the same as the argument, so that in many cases PRINT USR(5)
would print a value of 5.
Interrupts: NMI, IRQ, and BRK
We have mentioned the mechanical aspects of interrupt. Now let's look
at how to use the interrupt for simple jobs.
The IRQ connects through a vector in RAM; if we change the address
within the vector, we will change the address to which the interrupt goes.
The interrupt vector is located as follows:
Most PET/CBM: □□qD-ODRl (decimal lAA-lAS)
VIC/Commodore 64:D314-0315 (decimal 7flfl-7flq)
Before we change this vector, we should realize something quite important:
the interrupt does a lot of work sixty times a second. It updates the clock,
checks the RUN/STOP key, gives sen/ice to the cassette motors, flashes
the cursor, and handles keyboard input. If you thoughtlessly change the
IRQ vector, it will stop doing these things; and it's hard to handle a
118
MACHINE LANGUAGE FOR COMMODORE MACHINES
computer when it has a dead keyboard. You could try to program all these
functions yourself; but there's an easier way.
Suppose we use the vector to temporarily divert to our own program, and
at the end of our program we allow the interrupt to continue with whatever
it was going to do anyway. That way, our program would get service sixty
times a second, and the usually interrupted jobs would still get done.
It's not hard to do, and we can achieve many interesting effects by diverting
the interrupt. Remember that the interrupt runs all the time, even when
no BASIC program is running. By playing with the interrupt, we can make
a permanent computer system change that is in effect even when no
programs are in place.
Care must be taken in changing an interrupt vector. Suppose we are
beginning to change the two-byte address; we have changed the first byte,
and suddenly, the interrupt strikes. It will use an address that's neither
fish nor fowl: half is the old address, and half is the new. In such a case,
it's likely that the interrupt will become confused; and if the interrupt Is
confused, the whole computer is in trouble. We must find a way to prevent
interrupt from striking when we change the vector.
We could do this in machine language: before a routine to change the
IRQ vector, we could give the instruction SE I (set interrupt disable). After
this instruction is given, the IRQ cannot interrupt us. We may set the
vector and then re-enable the interrupt with the instruction CLI (clear
interrupt disable). Be sure that you do this, since the interrupt routine
performs many vital functions. We may say that we have masked off the
interrupt in the time period between execution of SEI and CLI. The NMI
interrupt, however, is non-maskable, and SEI will have no effect on it.
There's a second way of turning off the interrupt— that is, by shutting off
the interrupt source. Something makes an interrupt happen— it might be
a timer, it might be an external signal, or it might even be a screen event.
Whatever it is, we can get to the source of the interrupt and disconnect
it.
Almost all interrupt signals are delivered through an I R (interface adaptor)
chip; and these chips invariably allow the path of the interrupt signal to
be blocked temporarily. We'll discuss the I A chips later; for the moment,
the normal interrupt signals can be blocked with the following actions:
Commodore 64: Store $7F into address IDCDD (POKE 5t333, 127)
to disable; store $fll into the same address (POKE 5t333 ,lEq) to
re-enable.
STACK, USR, INTERRUPT, AND WEDGE
119
VIC-20: Store $7F into address $R1EE (POKE 371bb, 127) to dis-
able; store $C0 into the same address (POKE 371bt,l'=IE) to re-
enable.
PET/CBM: Store $3C into address $Efll3 (POKE SR-^ll, tD) to dis-
able; store $3D intothe same address (POKE 5'=i^ll,bl)to re-enable.
It goes without saying that the above POKEs should not normally be given
as direct commands; the first POKE in each case will disable the keyboard
(among other things), and you won't be able to type the restoring POKE.
A warning about interrupt programs: changing the IRQ vector is likely to
make it difficult to load and save programs. You may need to put the vector
back to its original state before you attempt any of these activities.
An Interrupt Project
The following project is written for the Commodore 64 only. The equivalent
coding for PET/CBM and VIC-20 may be found in Appendix E. Appendix
E, under Exercises for the Commodore 128, also contains appropriate
coding for the C128.
Let's write the coding for the interrupt itself. Sixty times a second, we'd
like to copy the contents of address $H1 to the top of the screen. Here
goes:
a 0330 LDR $qi
ft □33E STft $DADD
ft □3<1 JMP ($D3ftD)
Why the indirect jump? We want to "pick up" the regular interrupt routine,
but we don't know where it is yet. When we find the address, we'll put it
into locations $D3fta/$D3ftl so that the indirect jump will link things up
for us.
Now let's write the routine to enable the above interrupt coding. First, let's
copy the interrupt address from $ □ 3 1 ^ into the indirect address at $ □ 3 ft □ :
ft niAA LDft $Q31A
ft niAl STft $Q3ftD
ft 034ft LDft $0315
ft U3AJ) STft $D3ftl
Now we are ready to put the address of our own interrupt routine (at
$□330) into the IRQ vector:
A 0350 SEI
120
MACHINE LANGUAGE FOR COMMODORE MACHINES
A
□ 351
LDA
#$3C
A
□ 353
STA
$U31A
A
□ 35b
LDA
#$□3
A
□ 35fl
STA
$□315
A
□ 35B
CLI
A
□ 35C
RTS
We will enable the new interrupt procedure byaSYSto$D34<, above
(SYS a 3b). Before we give that command, let's write the coding to put
everything baci<:
A
□ 35D
SEI
A
□ 35E
LDA
$^3A^
A
□ 3bl
STA
$□314
A
Q3hA
LDA
$D3A1
A
□ 3fc7
STA
$□315
A
□ 3bA
CLI
A
□ 3bB
RTS
As you can see, we put the original address back, copying it from the
indirect address area where it was saved.
Once this code is in place, disassembled, and checked, you may return
to BASIC. SYS fl3t. will invoke the new interrupt code; SYS flfcl will
turn it off. Note that the character (a copy of the contents of address $"=11)
appears at the top left of the screen. The character seems to be affected
by pressing some keys; can you establish how many keys are involved?
Some models of Commodore 64 may print blue-on-blue when screen
memory is POKEd, as we are doing now. If so, the character may not
always appear in the left-hand corner. Project for enthusiasts: Fix this
problem by storing a value into the color nybble table at address $Dfl □□.
The I A Chips: P I A, VIA, and CIA
The interface adaptor (I A) chips are richly detailed. To understand them
fully, you'll need to read the specifications in some detail. Here, we'll give
their main functions.
PI A stands for peripheral interface adaptor, VIA for versatile interface
adaptor, and CIA for complex interface adaptor. There is speculation
among Commodore owners that the next interface chip will be called "FBI."
The functions performed by an interface adaptor are:
STACK, USR, INTERRUPT, AND WEDGE
121
1 . Event latching and interrupt control. We have noted that these chips can be
manipulated to block the interrupt signal. In fact, they do more than "gating"
the signal — allowing it through to the processor's IRQ trigger or alternatively
blocking it. They also often latch a signal into an event flag, sometimes called
an interrupt flag.
Latching is important. A triggering event may be brief; so short, in fact, that
the original signal causing interrupt might go away before the processor can
look at it. An Ifl event flag locks in the signal and holds it until the program
turns it off.
ON
INTERRUPTING -
EVENT
Figure 7.2
LATCH
EVENT
FLAG
OFF
COMPUTER
ACKNOWLEDGEMENT
If an event has time importance— that is, if the event's timing must be ac-
curately measured, or if the event flag must be cleared quickly so as to allow
for the detection of a new event— we may link the event flag to the interrupt
line. If we do so, the occurrence of the event will cause the processor to be
interrupted. We must write coding linked to the interrupt routines to detect
this event, clear the flag, and do whatever processing is needed. We set up
this link to the interrupt line by means of a register usually called the interrupt
enable register.
On the other hand, the event might not be particularly time critical. In this
case, you can simply check the appropriate event flag from time to lime.
When the event occurs, you may then clear the flag and handle it. No interrupt
is needed. Even when an event flag is not connected to the interrupt, it may
be called an interrupt flag; don't let the terminology confuse you.
Whether or not you handle these events through interrupt sequences, it's
important to know that It's your job to turn the event flag off. The flag will
hold the signal until it's turned off— and it usually won't turn off unless your
program takes some action to do this.
The various flags are triggered by timers or external signals. You can read
a flag's state by checking the interrupt flag register. Several flags will be
packed together in this register; as always, you will use the logical operators—
AND, OR A, or EOE— to extract or modify the particular flags in which you
are interested. You may also use the IFR (interrupt flag register) to clear
the flags.
722
MACHINE LANGUAGE FOR COMMODORE MACHINES
2. Timing. Certain addresses witfiin thie I A cliip are often assigned as "timers."
Ttiese timers count down; in othier words, if we place a value of $R? into a
timer and lool< at the value immediately, we might find that it has gone down
to $"^3. Timers come in many shapes and sizes— again, checl< the chip
reference for details— but most of them toggle an interrupt flag when they
have counted down to zero. As discussed, you may choose whether or not
this flag will really cause an interrupt signal.
3. Input/output. Certain addresses within the I a chip are connected to "ports,"
which extend outside the computer. Thus, the computer can detect external
events or control external devices. Output signals are usually latching in
nature: in other words, a store command might be taken to mean, "tum on
port 5 and leave it on."
Tips on lA Chips
Many addresses within an I A chip have a different meaning, depending
on whether they are being written to (stored) or read (loaded). Watch for
this when you are reading the chip specifications.
Often, the action required to turn an interrupt flag off is odd. It !ool<s like
the kind of thing you should do to turn the flag on. Keep in mind that a
flag may be turned on only by the external activity to which it is linked.
So, although it may seem odd to turn the flag in bit zero off by storing a
value of 1 (which would seem to want to turn bit zero on), don't worry.
You'll get used to it.
The lER (interrupt enable register) is often a source of problems. In many
cases, the high bit of a value we are storing has a special meaning: if it's
set, the other bits will cause the appropriate interrupt connections to turn
on; if it's clear, the other bits will cause the appropriate interrupt connec-
tions to be turned off. You may recall that we shut off the Commodore 64
interrupt by storing $7F into address $DCOD. This may seem odd: we're
storing a binary value of$Dlllllll, which might seem to be turning
bits on. In fact, the high bit of zero signals that all the remaining bits
are"turn off" signals; so the value causes all interrupts to be blocked.
Infiltrating BASIC: The Wedge
In zero-page, there's a subroutine that the BASIC interpreter uses fre-
quently to obtain information from your BASIC program. It's used to get
a character from your BASIC program, and to check it for type (numeric,
end-of-command, or other).
The routine is normally entered at either of two points: CHEGET, to get
STACK. USR. INTERRUPT, AND WEDGE
123
the next character from your BASIC program; and CHRGOT, to recheck
the last character. The subroutine is located at$DD7nto$DDfl7ln most
PET/CBM computers, and at $ □ □? 3 to $ □ □ fl A in VIC-20 or Commodore
64. You may disassemble it there if you wish. The coding is described
below.
Since CHRGET is in different locations, depending on the machine, the
following coding is shown with symbolic addresses. That is, instead of
showing the hex address value, the address is given a name, or symbol.
Thus, CHRGOT might represent address $DD7q, CHRGOT + 1 would
represent address $□□?&, and so on.
CHRGET INCCHRGOT + 1
BNE CHRGOT
INC CHRGOT + 2
CHRGOT LDA xxxx
This subroutine is self-modifying, that is, it changes part of itself as it runs.
That's not always a good programming technique, but it works well here.
The first part of the subroutine adds one to the address used by instruction
CHRGOT. This is a standard way of coding an address increment: add
one to the low byte of the address; if that makes it zero, the low byte must
have gone from $FF to $D0, in which case, add one to the high byte.
The address loaded by CHRGOT is within your BASIC program, or within
the input buffer if you have just typed a direct command. Before we follow
the next piece of code, let's look at our objectives:
1. If we find a space, go back and get the next character.
2. If we find a zero (BASIC end of line) or a colon (hex $3 A, BASIC end-of-
statement), we wish to set the Z flag and exit.
3. If we find a numeric, we wish the C flag to be clear; if we do not find a
numeric, we wish the C flag to be set.
CHRGOT LDA XXXX
CMP #$3A
BCS EXIT
If the character is a colon ($3 A), we'll leave the subroutine with the Z
flag set. That's one of our objectives. Here's part of another one: if the
character is $3 A or higher, it can't possibly be an ASCII numeric —
numerics are in the range of $3D to $3^.
CMP #$2D
BEQ CHRGET
124
MACHINE LANGUAGE FOR COMMODORE MACHINES
If the character is a space, we go back and get another character.
The following coding looks rather strange, but it's correct. After the two
subtractions, the a register will be back where it started:
SEC
SBC#$3D
SEC
SBC #$DD
After this, the R register is not changed; but the C flag will be set if the
number is less than $30, which means that it is not an ASCII numeric.
Additionally, the Z flag will bet set if a contains a binary zero. We have
met all our objectives and may now return:
EXIT RTS
Breaking Into BASIC
Since BASIC comes to this subroutine often, we can infiltrate BASIC by
changing this subroutine. Extra coding in this area is often called a "wedge"
program. We must be very careful:
• We must leave a, X, and Y unchanged; either we must not use them or we
must save them away and bring them back.
• We must not interfere with the flags.
• We must be careful not to slow BASIC down too much.
This is a tall order. The last requirement is often helped by two techniques:
use the wedge to implement extra commands in direct mode only; and
make use of a special character to identify our special commands.
In PET/CBM, we may choose to modify this subroutine in either of two
places: near the beginning, in CHRGET; or after the LDa, in CHRGOT.
Each location has its advantages. In the CHRGET area, we don't need
to preserve the a register or status flags, since CHRGOT will fix them up
for us. In the area following CHRGOT, we have the character we wish to
examine in the A register.
But in either case, it's an exacting job.
VIC-20 and Commodore 64 have made the job much more easy by pro-
viding a vector at address $03Dfl/$D3Dq that will give us control of the
computer, if we wish, immediately before each BASIC command is exe-
cuted. We still need to use due care, but we have much more latitude.
STACK, USR, INTERRUPT, AND WEDGE
125
The address of the instruction at C H R G T is often referred to as T X T P T R ,
the text pointer. This address always points to the BASIC command being
executed at the moment. If we want to participate in reading BASIC, we
must learn to use TXTPTR to get the information— usually by means of
indirect, indexed addressing — and to leave this address pointing at a suit-
able place when we return control bacl< to the normal BASIC handling
programs.
Project: Adding a Command
Let's add a simple command to the VIC and Commodore 64 by using the
$D3nfl vector. The ampersand (&) character isn't used in most BASIC
programs, so we'll make it mean this: whenever you see the code "&",
print ten asterisk (*) characters to the computer screen, followed by a
carriage return.
C128 note: Remember to check Appendix E, under Exercises for the
Commodore 128, for the appropriate coding.
As with our interrupt program, we'll copy the old address from $03Da/
03 into an indirect address location, so that we can link up with the
normal computer routines as necessary.
An important point: the vector will give us control, if we want it, with
TXTPTR positioned immediately before the next instruction. When we
return control to BASIC, we must be sure that TXTPTR is similarly po-
sitioned.
Here's our instruction "intercept":
a 0330 LDY #$□!
We're going to use indirect, indexed addressing to "look ahead" at the
instruction. Let's look, using TXTPTR as an indirect address:
A □33E LDA ($?&) ,Y
Since Y equals one, we'll look just beyond the address to which TXTPTR
is pointing:
a Q3AQ CMP
a BEQ $D3<7
a U3AA JMP ($D3aD)
If the character is an ampersand, we'll branch ahead to $0347. If not,
we'll connect through the indirect vector to the regular BASIC interpreter
code:
726 MACHINE LANGUAGE FOR COMMODORE MACHINES
ft U3A7 JSR $DD73
We may call CHRGET to move the pointer along. Now TXTPTR points
squarely at the ampersand character. We are ready to print ten asterisks:
ft
□ 3^ft
LDY
#$□□
ft
Q3AC
LDft
#$2ft
ft
03<E
JSR
$FFDa
ft
□ 351
INY
ft
0352
cpy
#$□&
ft
03SA
BCC
$a3^E
ft
035t
LDft
#$DD
ft
□ 35a
JSR
$FFDE
ft
□ 35B
JMP
$03AA
The above code prints an asterisk ($2 ft) ten times and then prints a
RETURN ($DD). It then goes to the regular BASIC interpreter, which will
look behind the ampersand character for a new BASIC command.
Now wei need to set up the link to our program. We'll write the code to do
this starting at $D35E, so that SYS fibE will put the new command
(ampersand) into effect:
ft
□ 35E
LDft
$D3Dfl
ft
□ 3bl
STft
$^3RD
ft
□ 3fc4
LDft
$D3DR
ft
□ 3t7
STft
$^3ftl
ft
□ 3fcR
LDft
#$3C
ft
□ 3fcC
STft
$D3^fl
ft
□ 3fcF
LDft
#$□3
ft
□ 371
STft
$D3^R
ft
□ 37^
RTS
When you have completed and checked the code (remember this is for
VIC and Commodore 64 only), return to BASIC. Type NEW and write the
following program:
lUO PRINT 3 A :&: PRINT 5 + b
IIU &
lED PRINT "THftT' S ftLL"
If you type RUN, you will get a SYNTftX ERROR in line !□□. We have
not yet implemented our "ampersand" command. Type the command SYS
flfcE. Now type RUN again. The ampersand command obediently prints
ten asterisks each time it is invoked.
Infiltrating BASIC isn't an easy job. But it can be done.
STACK, USR, INTERRUPT, AND WEDGE
727
Things You Have Learned
—The stack is located in page 1, from SDIFF moving down to $0100. It is
used for holding temporary information. A program may push information to
the stack, and then pull it back later. The last item that has been pushed onto
the stack will be the first item to be pulled back off.
— Great care must be taken to ensure that your program pulls exactly the same
number of items back from the stack as It pushed. In particular, be sure that
a branch or jump does not inadvertently omit a needed stack activity. A badly
handled stack is often fatal to the program run.
— PHA pushes the contents of A to the stack; PLA pulls from the stack into
the A register. These two commands are often used to temporarily save A.
PHP pushes the status register (S R); PL A pulls it back. These two commands
are often used for "deferred decisions."
— JSR pushes a return address (minus 1) to the stack; ETS recalls this ad-
dress. We may use JSR and RTS without needing to know the role the stack
plays, since the two commands take care of the details for us.
—Interrupts, including the BRK Instruction, push three items to the stack; RTI
brings them back so that the interrupted program may resume.
— USR is a function, as opposed to SYS, which is a command. DSR goes to
a preset address, takes a numeric argument, and can return a value. In
practice, DSR and SYS are used in quite similar ways.
— Commodore ROM systems contain coding for the interrupt sequences that
cause the data registers — A, X, and Y — to be pushed to the stack, and a
branch to be taken through an indirect address that the user can modify.
Since interrupt is active virtually all the time, it may be used to create activities
that are active even when no BASIC program is running.
— The various lA chips — PIA, VIA, and CIA — perform many different func-
tions, including: recording events in latching flags and controlling Interrupts;
timing; and connecting input/output ports. The detailed specification sheets
must be studied for these rather complex details.
—A subroutine called CHRGET is used frequently by the BASIC interpreter
when a BASIC program is running. We may modify or add to this subroutine
in order to add to or modify the BASIC language itself.
Questions and Projects
If you redirect the interrupt vector to your own machine language program,
you can copy all of zero page to the screen. Use indexing; start X at zero;
and walk through the whole of zero page, loading the memory contents
and storing (indexed again, of course) to the screen. Don't forget to connect
up your code to the regular interrupt entry address.
128 MACHINE LANGUAGE FOR COMMODORE MACHINES
You'll get a fascinating screen. There will be timers going, and as you
type on the keyboard you'll see various inner values changing around.
Enjoy the view.
It's sometimes suggested that a good way to pass information to a sub-
routine is to push the information onto the stack and call the subroutine.
The subroutine can pull the information from the stack. What's wrong with
this suggestion?
The above suggestion can be implemented, but it takes a lot of careful
stack work. You might like to work through the logic needed to do this.
There are some utility programs which, when placed in the computer,
allow a listing to be "scrolled." In other words, if the screen shows BASIC
lines E 5 □ to < fc □, the user can take the cursor to the bottom of the screen
and continue to press the cursor-down key. New BASIC lines (following
AhO) will then appear. This is not an easy thing to code, but here's the
question: do you think that this feature is done with a SYS command, a
wedge, or an interrupt technique? Why?
A SYS command from BASIC is like a subroutine call; so it must place
an address on the stack to allow RTS to return to BASIC. Take a look at
the stack and see if you can determine what address is used to return to
BASIC on your machine.
8
Timing,
Input/Output,
and
Conclusion
This chapter discusses:
• How to estimate the speed of your program
• Input and output from tape, disk, and printer
• Review of instructions
• Debugging
• Symbolic assemblers
• Where to go from here
131
132
MACHINE LANGUAGE FOR COMMODORE MACHINES
Timing
For many applications, maciiine language programs seem to run instan-
taneously. The speed of the 650x is much greater than that of other
devices, Including the human user. The machine language program usually
ends up waiting for something: waiting for the keyboard, waiting for the
printer, waiting for the disk, or waiting for the human to read and react to
information presented on the screen.
Occasionally, It may be Important to get fairly precise timing for a machine
language program. If so, the following rules of thumb may be kept In mind:
—All timing estimates are crude if the Interrupt routines are still active. The
effect of interrupt on timing can be crudely estimated by adding 10 percent
to the running time.
—Remember to allow for loops. If an instruction within a loop Is repeated ten
times, its timing will need to be counted ten times.
—The "clock speed," or memory cycle speed, of most Commodore machines
is roughly 1 microsecond — one millionth of a second. The precise number
varies from one machine to another, and also varies between North America
and other regions.
—Most instructions run at the fastest imaginable speed. Count the memory
cycles, and that's how fast the instruction will execute. For example,
LDa #$DD will need two memory cycles just to get the instruction— and
that's how fast it runs. LDR $0500 , X will usually take four memory cycles:
three to get the Instruction, and one to fetch the data from page 5. Exceptions:
no instruction runs in less than two cycles; and shift/rotate instructions, INC/
DEC, and JSR/RTS take longer than you might expect by this rule.
—Branches time differently, depending on whether the branch is taken (three
cycles) or not taken (two cycles).
— When a page boundary is crossed, the computer needs an extra cycle to do
the arithmetic. If the program branches from $DFE^to$lDa3, there will
be an extra cycle; if we LDR $E^E7 , Y, there will be an extra cycle if Y
contains a value of or greater.
Detailed timing values can be obtained from most tables of instructions.
Let's take a simple routine and estimate its timing. The following program
logically RNDs the contents of IDQ locations from $17E0 to
□ 33C
n33E
Q34D
Q3A3
LDX #$□□
LDA #$□□
AND $17ED,X
INX
TIMING, INPUT/OUTPUT, AND CONCLUSION
133
U3AS CPX
03^7 BCC $D34D
□3<q RTS
We may work out timing as follows:
LDX #$□□— executed once:
LDA #$□□— executed once:
AND $17ED , X: 32 times at 4 cycles:
128
2
2
68 times at 5 cycles (page cross):
I NX— 100 times at 2 cycles:
CPX 100 times at 2 cycles:
BCC— 99 times at 3 cycles:
340
200
200
297
1 time at 2 cycles (no branch):
RTS— 6 cycles:
2
6
Total time: 1171 cycles, or slightly over one thousandth of a second. We
might add 10 percent to allow for the effects of interrupt; and since this is
a subroutine, we could also add the extra six cycles needed to perform
the JSR.
Where timing is critical, the interrupt could be locl<ed out with SEI. Be
careful: it's seldom necessary, and is potentially dangerous.
We know that calling the kernal routine CHRODT at $FFD5 will send an
ASCII character to the screen. We may also redirect output to any logical
file.
We have seen that we may obtain input from the keyboard buffer into the
fi register by calling kernal routine GETIN at $FFE4. We may also
redirect the input so that we draw information from any logical file.
The same commands— $FFDE and $FFE4— still perform the input and
output. But we "switch" either of them to connect to a chosen device — or
more accurately, a chosen logical file. The file must be open; we may
switch to the file, and then switch back to normal I/O as we wish.
We use subroutine CHKODT at address $FFC9 to switch output to a
logical file. When we want to restore output to the screen, we call sub-
routine CLRCHN at $FFCC. This is not the same as an OPEN and
Input and Output
Switching Output
134
MACHINE LANGUAGE FOR COMMODORE MACHINES
KEYBOARD
SCREEN
INPUT
DEVICES
CHKIN ($FFC6)
SETS THE
INPUT SWITCH
OUTPUT
DEVICES
CHKOUT ($FFC9)
SETS THE
OUTPUT SWITCH
CLRCHN ($FFCC)
RESTORES BOTH
SWITCHES TO "NORMAL"
Figure 8.1
CLOSE— we simply connect to the file and disconnect, and we can do
this as many times as we want.
Subroutine: CHKOUT
Address: $FFCq
Action: Switclies the output path (used by CHROUT, $FFD5)
so that output is directed to the logical file specified in the
X register. The logical file must previously have been
opened.
The character subsequently sent by $FFDE is usually ASCII (or PET
ASCII). When sent to the printer, special characters— text/graphics,
width— will be honored in the usual way. Similarly, disk commands can
be transmitted over secondary address 15 if desired; a logical "com-
mand channel" file must be previously opened.
Registers: Registers A and X will be changed during the CHKOUT
call. Be sure to save any sensitive data in these registers before calling
CHKOUT.
Status: Status flags may be changed. In most recent Commodore
machines, the C (carry) flag indicates some type of problem with con-
necting to the output channel.
To switch output to logical file 1, we would need to follow these steps:
TIMING, INPUT/OUTPUT, AND CONCLUSION
135
1. Load a value of 1 into X (LDX #$□!).
2. JSR to address $FFCq.
Once the output is switched, we may send as many characters as we
wish using subroutine $FFDE. Eventually, we must disconnect from the
logical file and return to our default output, the screen. We do this by
calling subroutine CLRCHN at address $FFCC.
Subroutine: CLRCHN
Address: $FFCC
Action: Disconnects input and output from any logical files and
restores them to the "default" input and output channels,
keyboard and screen. The logical files are not closed, and
may be reconnected at a later time.
Registers: Registers A and X will be changed during the CLRCHN
call. Be sure to save any sensitive data in these registers.
Status: Status flags may be changed. In most recent Commodore
machines the (carry) flag indicates some type of problem with output.
The logical file concept is important. I may send to any destination —
cassette, printer, disk, or screen— without knowing which device is in-
volved. I send the characters on their way and the operating system sees
that they are delivered wherever they need to go.
This simplifies the machine language programmer's job. It's a simple task
to send the characters to some logical channel; the programmer does not
need to take special coding action depending on which device is involved.
Output Example
If we wanted to print the message HI on the printer, we might code as
follows.
0128 note: Remember to check Appendix E, under Exercises for the
Commodore 128, for the appropriate coding.
First, we'll open the printer channel in BASIC. Let's use logical file num-
ber 1:
IDO OPEN 1,A
iiu SYS aaa
lEO CLOSE 1
If you don't have a printer, you may open the file to cassette (OPEN
136 MACHINE LANGUAGE FOR COMMODORE MACHINES
1 , 1 , E) or to disk (OPEN 1 , fl , 3 , " □ : DEMO , S , W"). The machine
language program won't care: it will send to logical file number 1 no matter
what it is; it might even be the screen (OPEN 1 , 3). Let's write the coding:
A 0330 LDX #$□!
a 033E JSR $FFCq
Now the output is connected to logical file 1. Let's say HI:
R
□ 3<1
LDA
fi
□ 3^3
JSR
$FFDE
A
□ 3-^^
LDA
fi
□ 3-^13
JSE
$FFDE
A
□ 34B
LDA
#$DD
A
□ 3^D
JSR
$FFDE
A
□ 350
JSR
$FFCC
A
0353
RTS
Don't forget to send the RETURN— the printer needs it. After the machine
language program says HI, the program will return to BASIC and close
the file. Notice that the machine language program doesn't care what it's
saying HI to ... it sends the data to logical file 1.
Switching Input
We use subroutine CHKIN at address $FFCt to switch input so as to
draw data from a logical file. When we want to restore input from the
keyboard, we call subroutine CLRCHN at $FFCC. Again, this is not the
same as an OPEN and CLOSE— we simply connect to the file and dis-
connect, and we can do this as many times as we want.
Subroutine: CHKIN
Address: $FFCt
Action: Switches the input path (used by GET, SFFE-;;) so that input is
tai<en from the logical file specified in the X register. The logical
file must previously have been opened.
The character subsequently obtained by $FFE4 into the R register is usually
ASCII (or PET ASCII). A binary zero received from a file usually represents exactly
that: an input character whose value is CHR$(0); this is different from keyboard
GET where a binary zero means "no key pressed." When accessing a file, ST
(address $^0 for VIC and Commodore 64, for most PET/CBM) is used
for its usual functions of signalling end-of-flle or error. Similarly, disk status in-
formation can be received over secondary address 1 5 if desired; a logical "com-
mand channel" file must be previously opened.
Registers: Registers A and X will be changed during the CHKIN call. Be sure
to save any sensitive data in these registers before calling CHKIN.
Status: Status flags may be changed. In VIC and Commodore 64, the C (carry)
flag indicates some type of problem with connecting to the input channel.
TIMING, INPUT/OUTPUT, AND CONCLUSION
737
To switch input to logical file 1 , we would need to follow these steps:
—Load a value of 1 into X (LDX #$01)
— JSR to address $FFCE..
Once the input is switched, we may obtain as many characters as we wish
using subroutine $FFE<. Eventually, we must disconnect from the logical
file and return to our default input — ^the keyboard. We do this by calling
subroutine CLRCHN at address $FFCC. This is the same subroutine that
disconnects output from a logical file.
Input Example
We can write a program to read an input file from disl< or cassette. First,
let's write the file. We open the file according to its type:
Disk: OPEN l,a,3, "0:DEMO,S,W"
Cassette: OPEN 1,1,1
C128 note: Remember to check Appendix E, in the section. Exercises for
the Commodore 128, for the appropriate coding.
This may be done with a direct statement. Now let's write a few things to
the file:
PRINT#1, "HELLO THIS IS A TEST"
PRINT#1, "THIS IS THE LAST LINE"
CLOSE 1
If we have typed in the above statements correctly, we should have a
completed sequential file written on cassette or disk. Before writing the
machine language input program, let's examine how we might read the
file back in BASIC:
Disk: IDO OPEN l,fl,3, "DEMO"
Cassette: !□□ OPEN 1
IID INPUT #1,X$
ISD PRINT X$
130 IF ST = D GOTO 110
140 CLOSE 1
We might alternatively have written lines 110 and 120 as
110 GET #1,X$
lED PRINT X$ ;
This more closely approximates the logic flow of our machine language
program, since it will get the characters one at a time. If you are unsure
738
MACHINE LANGUAGE FOR COMMODORE MACHINES
about the role of ST, read up on it. We will use the same variable (at its
address of $ R □ or $ R t) to do exactly the same thing in machine language.
Type NEW and enter the following program:
Disk: 100 OPEN 1, a, 3, "DEMO"
Cassette: 100 OPEN 1
110 SYS aaa
lED CLOSE 1
We will read the file and copy it to the screen entirely in machine language.
Let's start coding at $ 0330 :
a D33C LDX #$□!
a □33E JSR $FFCt
Now the input is connected to logical file 1. Let's get information from it
and put it on the screen:
a 03^1 JSR SFFE-^
a JSR $FFDE
We must check ST as we would in BASIC. ST might be at either of two
addresses, depending on the system:
VIC, Commodore 64: R 03^7 LDR SRD
CBM/PET: fi 03^7 LDA S^fc
If ST is zero, there is more to come from the file; we may go back. If ST
is nonzero, there could be an error or we may be at the end of the file. In
either case, we don't want to read more from the file.
ft DIA"^ BEQ $03-^1
a □3'^B JSR $FFCC
a Q3A-E RTS
Check it and try it. The file is delivered to the screen quickly.
A File Transfer Program
Let's write a program to transfer a sequential file from any common device
to any other. BASIC will sort out which files to handle; once the files are
opened, machine language will take from and deliver to the appropriate
logical devices as desired.
C128 note: Remember to check Appendix E, in the section, Exercises for
the Commodore 128, for the appropriate coding, both BASIC and machine
language.
TIMING, INPUT/OUTPUT, AND CONCLUSION
739
It's not a good idea to switch input and output at tiie same time — in otfier
words, to call both $FFCt and $FFCR without canceling either via $FFCC.
The l<ernal doesn't mind, but it confuses the peripheral devices, which
expect to have exclusive occupancy of the data bus to the computer. So
we'll follow the pattern: switching on, sending or receiving, switching off,
and then going to the other device.
One more thing. S T tells us the status of the last device handled. Consider:
if we input a character, then output a character, and then checl< the value
of ST, we have a problem. ST will not tell us about the input, since the
last device handled was output; thus, we won't know if we are at the end
of the file or not. In machine language, as in BASIC, we must code carefully
to solve this problem.
Here comes BASIC:
lOD PRINT "FILE TRaNSFER"
110 INPUT "INPUT FROM (DISK, TAPE)";A$
lEO IF LEFT$(a$,l) = "T" THEN OPEN 1:G0T0 IbD
13D IF LEFT$(fi$,l)<> "D" GOTO IID
l^D INPUT "DISK FILE NAME" ;N$
15D OPEN l,fl,3,N$
IbD INPUT "TO (DISK, TAPE, SCREEN)";B$
17 □ IF LEFT$(B$,1) = "S" THEN OPEN 2,3: GOTO
IflD IF LEFT$(B$,1) = "D" GOTO aiD
1^0 IF LEFT$(B$,1) <> "T" GOTO ItD
^□0 IF LEFT$(A$,1) = "T" GOTO ItD
21D INPUT "OUTPUT FILE NAME" ;F$
BED IF LEFT$(B$,1) = "D"
THEN OPEN a,fl,^,"D:" + F$ + ",S,W"
530 IF LEFT$(B$,1) = "T" THEN OPEN a,l,l,F$
BAD SYS XXXX
ESQ CLOSE e:CLOSE 1
We'll work this out for the Commodore 64 computer; you can adjust it for
PET/CBM or VIC-20. The above BASIC program should not take up more
than 511 bytes; on a standard Commodore 64, that means that we'll have
clear space for our machine language program starting at $DAQD (dec-
imal 55fc0). We'll move the start-of-variables along, of course, so that
our machine language program won't be disturbed by them.
When we first type line E^D, we won't know what SYS address to use.
After the program is typed in (with SYS xxxxat line E< □), we can easily
confirm that the machine language can start at $□ ADD by checking the
140
MACHINE LANGUAGE FOR COMMODORE MACHINES
start-of-variables pointer. We go back and change E^DtoSYS EBfcO;
now we're ready to put in the machine language code:
ft OftDD LDX #$□!
ft DftDE JSR $FFCfc
a OftDB JSR $FFE4
By this time, we have a character in the ft register from the input source.
We also have a value in ST, telling us if this is the last character. Let's
examine the ST problem: we must check its value now, since ST will be
changed after we do the output. But we don't want to take any action
based on ST yet; we must first send the character we have received. Let's
check ST, and put the results of the check onto the stack:
ft DftDfl LDX $RD
ft DftOft PHP
If ST is zero, the Z flag will be set; we'll preserve this flag along with the
others until we call it back from the stack. If you are adapting this program
for the PET/CBM, don't forget that S T is at address $ R b for your machine.
The next thing we want to do is to disconnect the input by calling $FFCC;
but this will destroy the ft register. How can we preserve this value? By
transferring to another register, or by pushing ft to the stack. Let's do that.
There will now be two things on the stack.
ft DftDB PHft
We are now free to disconnect from the input channel and connect to the
output. Here we go:
ft OftOC JSR $FFCC
ft DftOF LDX #$D2
ft Dftll JSR $FFCH
ft Dftl4 PLR
The ft register gets back the last thing saved to the stack, and that, of
course, is our input character. We're ready to send it to the output device:
ft ORIS JSR $FFDE
ft Oftia JSR $FFCC
Now we may pick up on the condition of S T that we stacked away earlier.
Here come the flags that we stored:
ft DftlB PLP
TIMING, INPUT/OUTPUT, AND CONCLUSION
141
If the Z flag is set, we want to go back and get another character. If not,
we're finished and can return to BASIC, allowing BASIC to close the files
for us:
A OAIC BEQ $□&□□
a OaiE RTS
Important: Before running this program, be sure to move the start-of-
variables pointer ($DOeD/$OOEE) so that it points at address $DftlF;
othenvise, the BASIC variables will destroy this program.
Review: The Instruction Set
We started with the load, save and compare for the three data registers:
LDA LDX LDY
STA STX STY
CMP CPX CPY
The instructions are almost identical in action, although only the A register
has indirect, indexed addressing modes. We continued with the logical
and arithmetic routines that apply only to A:
AND ORA EOR ADC SBC
Arithmetic also includes the shift and rotate instructions, which may be
used on the A register or directly upon memory:
ASL ROL LSR ROR
Memory may also be directly modified by the increment and decrement
instructions, which have related instructions that operate on X and Y:
INC DEC
INX DEX
INY DEY
We may transfer control by means of branch instructions, which are all
conditional:
BEQ BCS BMI BVS
BNE BCC BPL BVC
. The branch instructions can mal<e only short "hops"; the jump instruction
is unconditional:
JMP
142
MACHINE LANGUAGE FOR COMMODORE MACHINES
Subroutines are called with the jump-subroutine, and returned with return-
from-subroutine; we may also return from interrupts:
JSR RTS RTI
We may modify any of several flags with the appropriate set or clear
command. Some of the flags control internal processor operation: for ex-
ample, the I (interrupt disable) flag locks out the interrupt; the D (decimal
mode) affects the way the ftDC and SBC work with numbers.
SEC SEI SED
CLC CLV CLI OLD
We may transfer information between the A register and X or Y; and for
checking or setting the stack location, we may move the stack pointer to
X, or X to the stack pointer. The latter is a powerful command, so use it
with care.
TftX TRY TSX
TXR TYfi TXS
We may push or pull information from the stack:
PHa PHP
PLA PLP
There's a special test, used mostly for checking I A chips:
BIT
The BIT test is used only for specific locations: no indexing is allowed.
The high bit from the location being tested is transferred straight to the N
flag. The next highest bit (bit b) goes straight to the V flag. Finally, the Z
flag is set according to whether the location has any bits set that match
bits set in the ft register. Thus, we can check a location with BIT $ ... .
followed by BMI to test the high bit, or BVS to test bit fc, or BNE to test
any selected bit or group of bits. It's a rather specialized instruction, but
useful for testing input/output ports.
Finally, the instruction that does nothing, and the BRK instruction that
causes a "false interrupt," usually taking us to the monitor:
NOP BRK
That's the whole set. With these instructions, you can write programs to
make the computer do whatever you choose.
TIMING, INPUT/OUTPUT, AND CONCLUSION
143
Debugging
When a program has been written, the next step is to look for any possible
errors, or bugs. The process of searching for and systematically elimi-
nating these bugs is called debugging.
Most programs are made up of sections, each of which has a clear task
to perform. When a program misbehaves, it may be easy to go to the area
of the bug, since you can §ee which parts of the program are working and
where things start to go wrong.
In case of doubt, you may insert breakpoints into your program. Replace
selected instructions with the instruction BRK; this may be done by re-
placing the instructions' op codes with the value □□. Run the program;
when it reaches the first breakpoint, it will stop and the machine language
monitor will b^icome active. Examine the registers carefully to see whether
they contain the values expected. Display memory locations that the pro-
gram should have written; the contents will tell you whether the program
has been doing its job correctly.
When you have confirmed that the program is behaving correctly up to
the breakpoint, replace the BRK command at that point with the original
op code. Command . G to that address, and the program will continue to
the next breakpoint. If it helps your investigation, you may even change
memory or registers before continuing program execution.
If you carried this procedure to the extreme, you might stop your program
after every instruction. It would take time, but you would certainly track
down everything the program did.
The best debugging takes place at the time you write the program. Write
sensibly, not "super cleverly." If you fear getting caught in an endless
loop, insert a stop key test (JSR $FFE1) so that you'll still have control
of the computer.
Get to know your machine language monitor. The monitor uses a number
of locations in memory; you'll have trouble debugging a program if it uses
the same storage addresses as does your program. Every time you try to
check the contents of a memory location to see what your program has
done, you'll see the monitor working values instead — and that would be
misleading and annoying.
Symbolic Assemblers
Throughout these exercises, we have used small, "nonsymbolic" assem-
blers such as would be found within a machine language monitor. These
144 MACHINE LANGUAGE FOR COMMODORE MACHINES
are good for beginners; they parallel the machine code quite closely and
allow you to keep the working machine clearly in focus.
As you write bigger and better programs, these small assemblers will be
less convenient. Forward, branches and subroutines we have not yet writ-
ten make it necessary for us to "guess" at the address and fix up our
guess later. There is the possible danger that an address will be typed in
wrongly ($03^5 instead of $03 5^), causing the program to fail.
To help us write more ambitious programs, we may wish to turn to com-
mercially available assembler systems that allow labels or symbolic ad-
dresses. If we wish to write code to call a subroutine to input numbers —
we might not have written this subroutine yet— we can code JSR NUMIN.
When we write the subroutine, we'll put the identifying label NUMIN at the
start. As your program is assembled, the proper address of NUMIN is de-
termined, and this address will be inserted as needed.
It saves work and helps guard against errors. But symbolic assemblers
allow a more powerful capability: they help documentation and allow pro-
gram updating.
Your assembly may be listed to the printer. This allows you to examine
and annotate the program, and file the details away for later reference.
The assembler allows you to include comments, which improve the read-
ability of the listing but don't affect the machine language program.
The source program you have written may be saved and used again later.
If you find it is necessary to change the program, bring back the source
code from cassette or disk, make the changes, and reassemble. In this
way, programs can be easily corrected or updated.
Where To Go From Here
Almost anywhere. Up to this point, we've been building confidence: trying
to give you a feel as to how the pieces work. Now, the real fun— the
creative programming — is up to you.
Users have varying objectives. You may want to do mathematical oper-
ations. You may want to interact upon BASIC programs— analyzing,
searching, renumbering. Whatever suits you. Your interest area may be
music, graphics, or animation. Machine language will open the door to all
of these; its amazing speed makes spectacular effects possible. You may
plan to go into hardware and interface new devices to your computer; an
understanding of machine language, and IR chips in particular, will be
useful. The possibilities are endless.
TIMING, INPUT/OUTPUT, AND CONCLUSION
745
Even if you have no immediate plans to write new programs in macliine
language, you will have gained an insight into the worl<ings of your ma-
chine. Everything that the machine does — BASIC, l<ernal, everything — is
either hardware or machine language.
With the elementary concepts we have introduced here, you will be able
to go deeper into more advanced texts. Many programming books deal
with the abstract 650x chip. That's hard for the beginner; it's difficult to
see how the instructions fit within the architecture of a real machine, or
how the programs can actually be placed within the computer. By now,
you should be able to take a piece of abstract coding and fit it into your
system.
Many things start to happen at once when you take your first steps in
machine language programming. You must learn how to use the monitor.
You must learn a good deal about how your machine is designed. And
you must learn how to fit the pieces together. It takes a while to adapt to
the "information shock"— but things start to fit together. Eventually, you'll
have a stronger and sounder view of the whole computer: hardware, soft-
ware, languages, and usage.
What You Have Learned
— Machine language programs can have run times estimated fairly accurately.
In many cases, however, machine language is so fast that detailed speed
calculations are not needed.
— We can handle input from devices other than the keyboard by switching the
identity of the designated input device. If an input channel has been opened
as a file, we may connect to it with JSE $FFCEj and disconnect with JSR
$FFCC.
— We can handle output to devices other than the screen by switching the
identity of the designated output device. If an output channel has been opened
as a file, we may connect to it with JSR $FFCR and disconnect with JSR
$FFCC.
— Once input or output has been switched, we may receive in the usual way
with the subroutine at $F7EA, or send in the usual way with the subroutine
at $FFDE.
— Be careful not to confuse connecting to a channel with opening a file. In a
typical program, we open a file only once, but we may connect to it and
disconnect from it hundreds of times as we read or write data.
— You have met all the instructions of the 650x microprocessor. There are
enough for versatility, but not so many that you can't keep track of them all.
146 MACHINE LANGUAGE FOR COMMODORE MACHINES
You have made a worthwhile start in the art and science of machine language
programming.
Questions and Projects
Write a program to read a sequential file and count the number of times
the letter "A" (hex Al) appears in the file. Use a BASIC PEEK to print
the value. You may assume that "A" will not appear more than 555
times.
Rewrite the above to count the number of occurrences of the RETURN
character ($ DD) in a sequential file. Allow for up to b 5 5 3 5 appearances.
Can you attach a meaning to this count?
Write a program to print HAPPY NEW YEAR to the printer ten times.
If you own a disk system, you know that you can scratch a program named
JUNK by using the sequence:
OPEN 15 , a , 15 : PRINT#15 , "SD : JUNK". Convert the PRINT#
statement to machine language and write a program to scratch JUNK.
Careful: don't scratch a program that you will need.
Write a "typewriter" program to read a line of text from the keyboard and
then transfer it to the printer. It will be a more useful program if you show
what is being typed on the screen and if you write extra code to honor
the DELETE key.
A
The 6502/
6510/6509/
7501/8500
Instruction
Set
The four chips differ only in their use of addresses and 1 :
On the 6502, the addresses are normal memory.
On the 651 and 7501 , address □ is a directional register and address 1 Is an
input/output register, used for such things as cassette tape and memory control.
On the 6509, address □ Is used to switch program execution to a new memory
bank; address 1 Is used to switch the memory bank accessed by the two
instructions LDfl ( • • ) / Y and STA ( . . ) / Y-
147
148 MACHINE LANGUAGE FOR COMMODORE MACHINES
Addressing Modes
Accumulator Addressing — This form of addressing is represented witfi a
one byte instruction, implying an operation on the accumulator.
Immediate Addressing — In immediate addressing, the operand is con-
tained in the second byte of the instruction, with no further memory ad-
dressing required.
Absolute Addressing— \r\ absolute addressing, the second byte of the
instruction specifies the eight low order bits of the effective address while
the third byte specifies the eight high order bits. Thus, the absolute ad-
dressing mode allows access to the entire 64K bytes of addressable mem-
ory.
Zero Page Addressing — The zero page instructions allow for shorter code
and execution times by only fetching the second byte of the instruction
and assuming a zero high address byte. Careful use of the zero page can
result in significant increase in code efficiency.
Indexed Zero Page Addressing— (X, Y indexing)— This form of address-
ing is used in conjunction with the index register and is referred to as
"Zero Page, X" or "Zero Page, Y." The effective address is calculated by
adding the second byte to the contents of the index register. Since this is
a form of "Zero Page" addressing, the content of the second byte refer-
ences a location in page zero. Additionally, due to the "Zero Page" ad-
dressing nature of this mode, no carry is added to the high order eight
bits of memory and crossing of page boundaries does not occur.
Indexed Absolute Addressing— {X, Y indexing)— This form of addressing
is used in conjunction with X and Y index register and is referred to as
"Absolute, X," and "Absolute, Y." The effective address is formed by
adding the contents of X and Y to the address contained in the second
and third bytes of the instruction. This mode allows the index register to
contain the index or count value and the instruction to contain the base
address. This type of indexing allows any location referencing and the
index to modify multiple fields resulting in reduced coding and execution
time.
Implied Addressing— \n the implied addressing mode, the address con-
taining the operand is implicitly stated in the operation code of the instruc-
tion.
Relative Address/ng— Relative addressing is used only with branch in-
structions and establishes a destination for the conditional branch.
The second byte of the instruction becomes the operand which is an
"Offset" added to the contents of the lower eight bits of the program counter
APPENDIX A
149
when the counter is set at the next instruction. The range of the offset is
-lEflto +127 bytes from the next instruction.
Indexed Indirect Addressing— \n indexed indirect addressing (referred to
as [Indirect, X]), the second byte of the instruction is added to the contents
of the X index register, discarding the carry. The result of this addition
points to a memory location on page zero whose contents are the low
order eight bits of the effective address. The next memory location in page
zero contains the high order eight bits of the effective address. Both mem-
ory locations specifying the high and low order bytes of the effective ad-
dress must be in page zero.
Indirect Indexed Addressing— \n indirect indexed addressing (referred to
as [Indirect, Y]), the second byte of the instruction points to a memory
location in page zero. The contents of this memory location are added to
the contents of the Y index register, the result being the low order eight
bits of the effective address. The carry from this addition is added to the
contents of the next page zero memory location, the result being the high
order eight bits of the effective address.
Absolute Indirect— The second byte of the instruction contains the low
order eight bits of a memory location. The high order eight bits of that
memory location is contained in the third byte of the instruction. The con-
tents of the fully specified memory location are the low order byte of the
effective address. The next memory location contains the high order byte
of the effective address which is loaded into the sixteen bits of the program
counter.
Instruction Set — Alphabetic Sequence
ftSL
RDC
AND
Add Memory to Accumulator with Carry
"AND" Memory with Accumulator
Shift Left One Bit (Memory or Accumulator)
BEQ
BIT
BCC
BCS
Branch on Carry Clear
Branch on Carry Set
Branch on Result Zero
BNE
BMI
Test Bits in Memory with Accumulator
Branch on Result Minus
Branch on Result not Zero
BPL
BRK
Branch on Result Plus
Force Break
750 MACHINE LANGUAGE FOR COMMODORE MACHINES
BVC
Branch on Overflow Clear
BVS
Branch on Overflow Set
CLC
Clear Carry Flag
CLD
Clear Decimal Mode
CLI
Clear Interrupt Disable Bit
CLV
Clear Overflow Flag
CMP
Compare Memory and Accumulator
CPX
Compare Memory and Index X
CPY
Compare Memory and Index Y
DEC
uecremeni Memory uy vjne
DEX
Decrement Index X by One
DEY
Decrement Index Y by One
EOR
"Exclusive-OR" Memory with Accumulator
INL
incremeni iviernory oy kjuxs
T \T V
INX
incremeni inaex a uy une
T M V
IN I
incremeni inaex y oy v_»ne
JMP
Jump to New Location
JSR
Jump to New Location Saving Return Address
LDfi
Load Accumulator with Memory
LDX
Load Index X with Memory
LDY
Load Index Y with IVjemory
LSR
Shift One Bit Right (Memory or Accumulator)
NOP
No Operation
OR A
"OR" Memorv with Accumulator
PHA
Push Accumulator on Stack
PHP
Push Processor Status on Stacl<
PLR
Pull Accumulator from Stack
PLP
Pull Processor Status from Stack
ROL
Rotate One Bit Left (Memory or Accumulator)
ROR
Rotate One Bit Right (Memory or Accumulator)
RTI
Return from Interrupt
APPENDIX A
151
RTS
Return from Subroutine
SBC
Subtract Memory from Accumulator with Borrow
SEC
Set Carry Flag
SED
Set Decinmai Mode
SEI
Set Interrupt Disable Status
STfl
Store Accumulator in Memory
SIX
Store Index X In Memory
STY
Store Index Y in Memory
TAX
Transfei- Accumulator to Index X
TAY
Transfer Accumulator to Index Y
TSX
Transfer Stack Pointer to Index X
Txa
Transfer Index X to Accumulator
TXS
Transfer Index X to Stack Register
TYfl
Transfer Index Y to Accumulator
Programming Model
15
PCH
8 7
PCL
N
V
B
D
1
Z
c
ACCUMULATOR A
INDEX REGISTER Y
INDEX REGISTER X
PROGRAM COUNTER "PC"
STACK POINTER "S"
PROCESSOR STATUS REG "P"
L
CARRY 1 = TRUE
ZERO 1 = RESULT ZERO
► IRQ DISABLE 1 = DISABLE
► DECIMAL MODE 1 = TRUE
► BRK COMMAND
OVERFLOW
NEGATIVE
1 = TRUE
1 = NEG
Figure A.1
152
MACHINE LANGUAGE FOR COMMODORE MACHINES
<«
HI
m
O
CO
<"
LU LLl LU UJ LU LU
r- CO If) Q u.
LU
mco
<
ooooo
CM00<OUJ
can
<
LULUUJLiJUJLLlLiJLLJ
1
o
X-CM
N
0)DO
ZPAG Z,X Z,Y
2 2 2
(Ota
0>ffi
(0 CO CO (O (o
,-coior^ Qu.
CO
1
c<r
1
a
CM00<OUJ
OOO
<OUJ
tocococococococo
O CM Tt <o 00 < CJ UJ
(0
T3
c
(U
0)
00(0 jOO
CM
<
■o
o
o
<a:!llEC<oIliQs
a
O
5
z
o
CO
„X A,Y
3 3
oojoxn 0)0)0)0)
»- CO in 0) 00 Q u-
OaOQQOOO
t- CO in 0) OQ Q u.
QQQDQQQQ
O CM 't CO 00 < O UJ
C/)
OQ
<
oo
to
a
E
3
—>
<
(0
coco
Q
1
-)-)
<
XcM
»-coinr>-0)OQQLL
OCS'*<000<OIU
in in u) in in in in in
«-coinr*o>0QQu.
in in in in in in in in
OCM^(000<UUJ
o
<J>
1
in
o
<CM
0.
N
1
1
,c
(/>
T3
C
oooo
cor^cou.
2>UUJ
OQ CO QQ DO
o
1
<o
0)
O) 0) 0) 0) 0) 0) 0)
O CM CO < O UJ
0)
<D
•a
o
O
OOOO
in o>Q
u
c
i2
00
<QcnO<<£:o
$200^=0^00
0<llJ<C/)_lO(0
a
O
_jOOuj
q:>oz
OQ 00 00 OQ
1
u.
SED
1
Ul
^ a.
ii
1
Q
CLD
1
o
>-X
Is
1
oo
1
<
>-x
1
0)
<(/)
1
00
qh
1
r~
u]
(/)
1
CO
RTS
PLA
ROR-A
1
in
CLI
1
■>t
RTI
PHA
LSR-A
1
CO
SEC
1
CN
PLP
ROL-A
1
CLC
1
o
BRK
PHP
ASL-A
Ooo<
1 1 1
in
<u
■D
O
o
a
O
O)
c
(A
CM
<
S
3
g>
IL
APPENDIX A
153
CONDITION
CODES
N Z C 1 V 1
\
\
\
\
1
\
\
\
\
\
s
;
\
2
1
1
°
1
1
1
o
1
1
o
1
V
\
1
\
1
\
\
\
j
\
\
1
\
\
V
V
1
\
\
1
\
\
1
\
\
1
I
V
V
1
1
1
\
\
>
i
%
z
o
1
%
■o
z
c
CL
o
lative
CM
CM
cy
CM
CM
CM
CM
CM
z
—
<M
o
c
a.
O
£
s
°
s
>■
=*
m
m
m
to
CO
z
Q.
o
s
&
X
CO
CO
to
CO
CO
z
I-
•V
N.
rr
Q.
o
«
o
a
UJ
o
o
m
LU
LJ.
o
CD
X
CM
CM
CM
CM
CM
CM
to
i
z
CO
<D
«!■
NT
□l
O
o
S
>
=*
CJ
N
CM
™
CM
z
to
to
u>
c
Q.
o
n
a
ID
m
X
%
N
CM
<M
CM
CM
li
z
CO
CO
CO
e
0.
o
to
w
5
<
piled
*
-
-
-
-
-
z
cy
CM
CM
CM
CM
eg
CM
CM
E
Q.
o
s
GO
CO
O
s
s
g
s
CO
tli
8
E
-
z
CJ
Q.
o
s
d>
CM
CM
CM
CM
CM
CM
Z
CO
Ul
to
n
m
CO
in
CO
o
Q.
O
in
CM
S
m
O
^
LU
3
to
O
in
-t
CO
LU
«
to
to
CO
to
to
to
CO
CO
CO
CO
to
1
z
to
to
CO
CO
to
•V
a.
o
Q
CO
Q
(N
UJ
o
Q
O
O
tu
O
O
LU
O
O
UJ
UJ
8
o
<
%
CO
cv
CM
CM
CM
CM
?
z
CM
CM
CM
CM
CM
CM
E
e
Q.
O
•B
(0
o>
CM
O
8
5
NSTRUCTIONS
c
_g
(5
&
o
<
T
o
+
+
<
<
T
s
%
2
o
1
o
o
O
z
o
I
o
z
<
(£
03
o
z
o
X
o
z
<
a:
03
N
Z
o
X
o
z
<
X
03
$
z
z
o
I
o
z
<
03
o
11
N
z
O
X
o
z
<
tE
m
o
z
z
o
X
o
z
<
CE
03
<
o>
u,
a
9
«
o
>
z
o
X
o
z
2
03
>
Z
o
X
u
z
<
cc
CD
O
T
o
O
T
o
T
o
>
<
X
>
s
I
X
J;
X
>
>
<
T
>
<
S
X
+
X
I
+
X
>
+
>-
d
O
_j
UJ
z
R
-J
CM
<
!> 03
3. 3
w w
II
<
T
2
o
c
o
E
s
o
a
<
o
<
w
<
O
O
CD
w
o
m
2
m
1-
S
CO
UJ
z
CO
—I
Q.
CD
CC
CO
O
>
03
O
o
O
_i
o
O
>
d
O
X
Q.
O
>-
0.
o
o
LU
o
X
UJ
o
>
LU
O
cc
o
UJ
O
z
X
z
>
Z
0-
2
->
cc
<
o
_1
CO
<t
£
3
o>
il
154
MACHINE LANGUAGE FOR COMMODORE MACHINES
CODES
N Z C 1 V
1
1
1
\
\
1 1
1 1
1 1
1 \
\ \
\ c
1
;
1
1
1
1
V
\
;
1
;
1
1
1
\
\
(RESTORED)
1
1
\
\
\
1
\
\
\
(RESTORED)
1
\
1
\
\
1
1
1
I
1
j
1
1
1
1
1
1
\
\
1
1
\
1
1
\
i
!
>^
\
1
1
\
—
OJ
z
t
1
hi
O
tp
s
%
z
1
Q.
o
1
Z
0.
o
>
1
n
CO
CO
CO
z
m
o
tu
m
K
H:
« c
o
o
n
CO
CO
CO
Z
■* r
in
Ol
O
Q L
m I
u
n
O
LU
UJ
Q
a
Z, Page, xl
CM
>r
CM
CM
CM
CM
CM
OJ
z
D
CD
CO
V
o
m
m
(D
LO
s
(lnd.)Y 1
lO
CM
CM
z
u>
in
to
0.
o
tu
X
T
«
CM
M
CM
z
CO
CO
CD
0.
o
o
UJ
5
Implied 1
tb
T-
z
CM
CO
CO
CO
to
(M
CM
CM
CM
CM
CM
CM
CM
CM
fe
<;
UJ
C9
3
to
CO
CM
o
3
LL
<
<
<
m
Accum. 1
%
z
CM
CM
CM
0.
o
Zero Page 1
CM
CM
CM
CM
CM
CM
CM
n
P5
in
in
CO
n
to
Q.
o
(O
<
<
«
s
in
UJ
S
Absolute 1
CO
(0
CO
CO
<0
CO
(O
z
(D
(D
<D
xr
Q.
o
lU
<
UJ
T
O
o
lU
CM
UJ
Q
LU
Q
CO
m
CO
o
eo
1
i
E
%
CM
CM
CM
z
CM
CM
CM
a.
o
a
s
o>
UJ
INSTRUCTIONS 1
c
<
!
1
X
:
>
i i
<
03
to
(0
s
-
j:
CO
0]
S
<
01
X
+
Q.
CO
t
+
(0
i
b
i-
«i:
9 CO
.i> M
Z
OJ DC
<
<
O
T
Q
j;
I
2
I
X
<
>
i
X
<i
<
CO
■<
s
1
S
X
3
>-
3
§ 1
<
o
0.
a
X
0.
3
Q.
0.
§
cc
!2
o
cc
CO
o
Ul
o
UJ
0>
u)
m
X
?
>
X
S2
CO
U; m cQ
Q Q s. >
a O £ £
U: s s g
e )- s 2
O CD O „ O
S3 Z S X
CO < O UJ
12
b ^
UJ u
u. <
U. I-
UJ CO
O (£ IT
H m UJ
^ D. CL
S CC flC
X X 5 o O
UJ LU 8 s 2
ilSss
X 5- < S ^
O S UJ
UJ 0- oc
Sis;
O S St
„ p p
>- w tfl
c {E cr
< =J 3
o o o
zoo
=1 o o
§55
UJ z z
0. m m
U.
z z z
*- CM
o o o
O C3 Q
< < <
o N
9 °
53
B
Some
Characteristics
of Commodore
Machines
755
156
MACHINE LANGUAGE FOR COMMODORE MACHINES
PET— Original ROM
The first PET. It can be recognized by tlie message seen at power up:
*** COMMODORE BASIC ***
using asterisks but witli no identifying number after tlie word BASIC.
The original machine may be upgraded to Upgrade ROM by fitting a new
set of ROM chips. This is a good idea, since the original logic cannot
handle disk, does a poor job on cassette data files, has no built-in machine
language monitor, and has a zero page architecture that differs significantly
from all later PET/CBM's. The BASIC language on this unit is also limited;
arrays may not contain over 256 elements, for example.
This early machine is becoming rare.
PETICBM— Upgrade ROM
The first PET that can handle disk. It can be recognized by the message
seen at power up:
### COMMODORE BRSIC ###
using the numbers sign (or octothorpe, if you like).
This is much cleaner logic than the previous machine. Its internal structure
is similar to that of later PET/CBM units (the 4.0 machines), so that it has
much in common with them.
It does not have specialized disk commands such as CRTRLOG,
SCRATCH, or DLOAD (the 4.0 disk commands); but these are "conve-
nience" commands and the Upgrade ROM unit can do everything that the
later units do.
Upgrade ROM machines have a BASIC annoyance: under some circum-
stances, string variables need to be tidied up using a technique called
"garbage collection." This takes place automatically when needed; but
when it does, the machine will freeze and seemingly will be dead for a
period that may last from a few seconds to as long as a half hour or more.
PETICBM— 4.0 ROM and 80 Characters
This class of machine has been a mainstay of the Commodore line for
years. It may be recognized by the message seen at power up:
*** COMMODORE BASIC A . D ***
For the first time, a number appears in the message.
APPENDIX B
157
These machines are characterized by new BASIC disk commands
(CATaLOG, etc.) and elimination of garbage-collection delays. Their in-
ternal architecture, especially zero page, is quite similar to the previous
Upgrade ROM computers.
Some time after the initial production of 40-column machines, 80-coiumn
machines were introduced, as well as a new 40-column version called the
"fat 40." The later machines are distinguished by new screen/keyboard
features, most noticeable of which is that the cursor movement keys repeat
automatically.
Subsequently, two memory-expanded machines became available. The
8096 came fitted with 96K of RAM; the extra 64K was "bank switched"
into memory as needed in blocks of 16K. The SuperPET, too, had an
extra 64K of RAM that was bank switched in 4K blocks; it also came with
an additional microprocessor (the 6809) used primarily for implementing
high-level languages. Both the 8096 and the SuperPET may be used as
conventional CBM 8032 computers; the extra memory may be ignored.
VIC-20
The VIC-20 was a new design concept for Commodore. Color, graphics,
and sound were built into the computer. The memory architecture changed
radically. Zero-page locations were shifted significantly as compared to
previous PET/CBM computers.
BASIC reverted to Upgrade ROM style — no special disk commands and
potentially slow garbage collection. Other than that, BASIC was not trimmed.
All the functions and features remained, and some attractive new screen
editing features were added, such as automatic repeating keys.
The VIC comes with no machine language monitor; it's necessary to load
one. The SYS command has a new attractive feature that allows registers
A, X, and Y to be "preloaded" by POKGing values into addresses 780,
781 , and 782. Location 783 could also be used to set the status register,
but that's dangerous; unless it's done carefully, the decimal mode or in-
terrupt disable flags might be set inadvertently.
The VIC-20 is somewhat vexing for machine language programming work.
Depending on the amount of extra memory fitted (none, 3K, or 8K and
over), the location of start-of-BASIC and of screen memory will vary.
Commodore 64
The Commodore 64 has much in common with the VIC-20. In particular,
its zero page organization is almost identical to that of VIC. The Com-
158
MACHINE LANGUAGE FOR COMMODORE MACHINES
modore 64 comes with a 6510 microprocessor; addresses □ and 1 are
reserved for "banl< switching" of memory.
BASIC is identical to that of the VIC— no special disk commands and
potentially slow garbage collection. There's no built-in machine language
monitor, so one must be loaded. The SYS command, as with the VIC,
allows preloading of registers R, X, and I if desired.
The Commodore 64 has a more stable architecture than the VIC. BASIC
starts in a consistent place, and the screen is always at hex 00 unless
you move it. There's a bank of memory at $CODD to $CFFF that is not
used by the computer system; it's useful for staging machine language
coding.
The Commodore 64 is the first Commodore machine in which it is some-
times desirable to write totally in machine language, with no BASIC at all.
BASIC can be swapped out to release extra RAM, and large applications
(word processors, spread sheets, and so on) are likely to do this.
Commodore PLUS/4
Similar to the Commodore 64 in many ways. The processor is a 7501 ,
which has the same instruction set as the 6502. Screen memory and
BASIC RAM have been moved a little higher. BASIC itself is greatly ex-
panded.
Color and sound are implemented differently to the Commodore 64.
There's a built-in machine language monitor with expanded features, such
as assemble and disassemble. This one is convenient for machine lan-
guage programmers.
The memory arrangement is more sophisticated than on previous ma-
chines; large implementations may require insight into the machine's de-
tailed architecture.
B Series
The B-128, B-256, CBM-128, and CBM-256 were designed as successors
to the 80-column PET/CBM units. Architecture has been radically changed:
the processor is a 6509, memory is bank switched, and zero page is
significantly different from that of other models.
The cassette buffer is no longer at $033 □, so that the examples given
in this book will need to be moved to a new part of RRM (addresses
$□'';□□ to $n7FF are available). Bank switching is more complex than
on other models. Beginners will find that there are more things to be kept
APPENDIX B
159
track of in this machine. If possible, beginners should try to find a simpler
computer on which to take their first steps.
Implementation of large-scale programs require setting up a "transfer se-
quence" program to link the program's memory bank to that of the kernal.
Usually, a bootstrap program will be needed to set everything up.
A machine language monitor is built into this line of machines. A few new
commands have been made available: . V to switch banks, . @ to test
disk status.
160
MACHINE LANGUAGE FOR COMMODORE MACHINES
Commodore 128
The Commodore 128 is three machines in one.
1 . In C64 mode, It Is Identical In almost all aspects to the Commodore 64. As
such, the machine In this mode has access to only 64K of memory, and
normally uses only standard Commodore 64 peripherals and screen formats.
2. In CI 28 mode, It Is an extended version of the 64 with extra features: 128K
of memory (arranged In two banks of 64K per bank); the possibility of using
an 80-column screen; the possibility of interfacing a disk unit that will operate
at a much higher speed than that of the Commodore 64.
The C128 has extensive hardware compatibility with the Commodore 64.
The 64's standard disk and printer can be hooked up in the usual way, but
with no speed Improvement. Sound and 40-column graphics may be achieved
with POKES to the same memory locations as for the 64.
The processor used for the C64 and CI 28 is the 8500, which has the same
instruction set as other machines such as the Commodore 64. Machine
language software Is not generally upwardly compatible with the Commodore
64 because of differing RAM usage between the two machines.
3. CP/M mode uses the Z80-A microprocessor, whose machine language in-
struction set is completely different from that of the 650x. These are outside
the scope of this book.
Introduction (128)
The Commodore 128 may be used as if it were a Commodore 64 or in
CP/M mode. The following material deals with its use in CI 28 mode.
The Commodore 128 comes with a 8501 microprocessor. As in the Com-
modore 64, addresses □ and 1 are reserved for control ports.
BASIC is rich with extra commands, and there's a good built-in machine
language monitor, which will be useful for us. The SYS command allows
preloading of registers A, X, and Y if desired, and reading the contents
of these registers after a return to BASIC.
The Commodore 128 has a large amount of memory, and this calls for
an elaborate architecture. There is 128K of RAM, 44K of ROM, the input/
output chips, and the potential for much more ROM and RAM to be added
internally or through a cartridge. The processor can reach only 64K of
memory at a time, so that a sophisticated system of "memory banl<ing"
must be used to get access to everything.
The term "bank" is misleading; the word "configuration" might be more
appropriate. For example, when a programmer calls for BANK 13 the
APPENDIX B — COMMODORE 128
161
computer supplies a configuration which is partly RAM and partly ROM. A
call for BANK 1 5 would invoke a different configuration of RAM and ROM.
Some of the RAM and ROM are the same as in the previous configuration.
The details are not important at this stage, but a drawing of some of the
popular "bank" configurations might be helpful.
In this book, we will be using Bank 15 almost exclusively. That will allow
us to put our own programs into RAM at a low address in memory, and
call upon the built-in programs that are stored in ROM at high memory
addresses.
Since the Commodore 128 contains a "built-in" Commodore 64, it will not
be surprising to learn that many of the interface chips — for video, sound,
and other purposes— are almost identical to those of the Commodore 64.
Do not worry if all this sounds technical. You will learn about many of
these features as you go.
Here's the important thing to remember: when you reach the exercises
that are found in each chapter, check Appendix E, under Exercises for
the Commodore 128, to get the CI 28 version. The principles are the
same — we're doing the same thing using the same techniques — but small
adjustments are needed for the special characteristics of the Commodore
128.
If you have not read the main part of the book, stop here and return to
Chapter 1 . When you're ready to dig for more technical information, you
will find it here, and in Appendix E and Appendix C and Appendix H. But
first: read, learn, and enjoy.
Choosing a Bank for Your Program (128)
You can move from one bank to another, but it takes extra work. It's best,
when you can, to pick an initial bank configuration that you can live with
during the running of your program. A quick rundown of the most popular
configurations follows. Choose Bank 15 if you can.
First, a general rule: Addresses □ and 1 are reserved, and so are ad-
dresses hexadecimal FFDO to These addresses don't "bank" and
are always there. The 251 addresses above $FFD4 are bank switched,
but are seldom useful to the average programmer. In a standard C128,
addresses from $3to$D3FF always refer to RAM Bank regardless of
the bank selected.
Banks 0, 1, 2, and 3 are pure RAM— no ROM to help you do things, no
I/O chips to help you input and output data. Banks 2 and 3 are reserved
162 MACHINE LANGUAGE FOR COMMODORE MACHINES
FEFF
$00(^
"Bank 0"— Almost 64K of RAM. This is where BASIC programs are stored. RAM exists
above $FF04, but is not nomiaiiy used.
"Bank 1 "—Addresses from $0400 up are RAM 1 , where BASIC variables, arrays, and strings
are stored. Below $0400, RAM is used.
"Bank 1 3"— Below $8000, addresses RAM 0. Cartridge ROM (if present) occupies addresses
$8000 to $BFFF. From $000 to $FFFF, we have Kernal ROM, except for the area from
$D000 to $DFFF, which holds input/output chips.
APPENDIX B — COMMODORE 128
763
$0000 $E000
"Bank 14"— Memory below $4000 is RAM 0. From $4000 up, we have ROM for BASIC and
Kernel, except for a slot from $0000 to $OFFF, which contains the character generator ROM.
"Bank 15 '—Memory below $4000 is RAM 0. From $4000 up, we have ROM for BASIC and
Kemal except for a slot from $0000 to $OFFF, which contains input/output chips.
764 MACHINE LANGUAGE FOR COMMODORE MACHINES
for the addition of extra RAM. None of tliese are good configurations for
programs — you will always want to do input and output — but they are
often called in briefly to get or store data. Banl< uses the RAM that
normally holds BASIC programs; Bank 1 uses the RAM that holds BASIC
variables, arrays, and strings.
Banks 4, 5, 6, and 7 are similar to Banks 0-3 below address $flODO. A
set of ROM lies over the RAM at addresses $flDDDto$FFFF, except
for addresses $DDDD to $DFFF which contain I/O chip registers. This
ROM is internal, which means that it can be plugged into spare sockets
within the C128. Unless you plan to make your own ROM-like chips, in-
cluding your own Kernel program, stay away from these.
Banks 8, 9, 10, and 11 are similar to Banks 0-3 below address SflDDD.
A set of ROM lies over the RAM at addresses SflODQ to $FFFF, except
for addresses $DDDD to $DFFF which contain I/O chip registers. This
ROM is external, which means that it is plugged into the cartridge port.
Again, stay away; using these configurations calls for you to supply the
entire logic of the machine.
Banks 12 and 13 are similar to Bank below address $flODD. A set of
ROM (internal for Bank 12, external for Bank 13) lies over the RAM at
addresses IfiODD to $BFFF, and the standard Kernal ROM lies over
the RAM at addresses $CDDD to $FFFF, except for addresses $DODO
to $DFFF which contain I/O chip registers. These look good for the
average application if you don't need BASIC. You'll get lots of RAM memory
to play with, yet the I/O chips and Kernal are there and available to you.
Banks 14 and 15 are similar to Bank below address $^00D. System
ROM (Basic and Kernal) lies over the RAM at addresses OOD to $FFFF,
except for addresses $DDDO to $DFFF which contain the character
generator ROM (Bank 14) or I/O chip registers (Bank 15). These are the
easiest to use, especially Bank 15 with free access to I/O. The only
limitation is the more limited access to RAM for your program. Since you
still have over 12K of RAM to play with, that shouldn't be a major problem.
On rare occasions you may find a need to tuck a program into high RAM.
That makes the job harder. You will certainly be located beneath ROM,
and that means you need to call to make bank transfers as your program
calls the Kernal and returns. It can be done. But it is messier, and if you
can relocate your program to eliminate the problem, do so.
APPENDIX B — COMMODORE 128
765
Data in Other Banks (128)
Wherever your program ends up, you may find a need to reference data
in other banl<s— to load it, store it, or compare it. Three Kernal subroutines
are available to help you do these actions. They are:
Action Name Address
Load INDFET $TT7A
Store INDSTA $FF77
Compare INDCMP $FF7fi
All these use indirect, indexed addressing to reference the desired data.
Thus, you must set up the indirect address in zero page as usual and load
Y with the index value desired. You must give these subroutines two extra
pieces of information: where the indirect address is located, and what data
banl< is desired.
The indirect address information is passed to the subroutine in one of
several ways:
For INDFET, load the address to register A;
For INDSTA, put the address into location SDSBq;
For INDCMP, put the address into location $DECfl.
Indicate the desired bank (0 to 15) by loading its value into register X.
It is wise to lock out interrupts with SEI before starting any of the above
calling sequences; do not forget to release the interrupt with CLI after
the call. Chapter 6 has an example of these routines.
Jumping to Other Banks (0128)
A JMP is slightly easier than a JS R, but neither is hard. The call addresses
are:
Action Name Address Alternate
JMP JMPFAR $FF71 $DEE3
JSE JSRFAR $FFE.E $DECD
You must place the address of your desired destination into addresses E,
3, and A . Oddly, the address is not "backwards" like most 650x addresses.
The bank number goes into address E, the high address byte into 3, and
the low byte into address A. Address 5 is a "status register" image, if you
want it; usually it is best to leave this value as zero. If you want to pass
information via the processor's registers, the values must be stored in
766
MACHINE LANGUAGE FOR COMMODORE MACHINES
memory: a at fc, X at 7, and Y at fl. Remember, you must set up addresses
S to 4 before making the call.
The same setup applies to both JMPFARandJSRFRR. About the al-
ternate address: you cannot JMP or JSR to $FF71 or $FFtE /f frte
ROM isn't there— m which case you must use the alternate address in
low memory which is never switched. When you have everything set up,
you may JMP to JMPFftR, since you will not need to come back. You
must JSR to JSRFaR, and it's worth noting that this call will normally
return to Bank 15 only. If you want to look at registers after the return,
they will be saved in the locations noted above.
The Screen (C128)
The 40-column screen is mapped in the "usual" way. That is, whatever
characters are stored in screen memory (usually $D4DDto$07E7) will
be seen on the screen, and whatever appears on the nongraphics screen
may be inspected at the corresponding point within memory. Material
dealing with how to use the 64's video chip will normally be valid for the
128.
The 80-coiumn screen is driven in an entirely different manner. The char-
acters on screen are mapped from memory — but not the computer's main
memory. Instead, the video controller uses a "private" memory. We have
to do a moderate amount of work to inspect or change this memory; a
minimum of six commands are usually needed to reference a screen
memory byte. For an illustration of the cumbersome method needed to
do this, look at the character stored in the second position of the top row
of the 80-column screen. The internal memory address of this character
is □ DDI (high byte □, low byte 1); here we go. POKE 547fl4 , Ifl : POKE
SA76A,D to set the high address byte. POKE 547fl< , iq : POKE
SA7&A,l to set the low address byte. Finally, POKE
5 4 7 a 4 , 3 1 : P R I N T PE E K ( 5 ^ 7 a 5 ) . We'll f inally get the character
(in screen code, not ASCII) ... but that's a lot of work compared to a
single PEEK on 40 columns.
This system is not all bad. For one thing, blocks of "private" memory can
be moved internally to provide for fast scrolling. For another, the 80-column
controller has no need to dip into main memory to keep its screen alive;
with the result that the 80-column machine can be much faster than the
40-column one, which needs to reference memory almost continuously.
c
Memory
Maps
A word about memory maps: they are always too big or too small for the
use you have in mind.
The beginner may feel swamped by the wealth of detail. There's no threat,
however. The information is there when you're ready for it. Browse through
the information; it may be thought-provoking. Try reading or changing
locations to see what happens.
The advanced programmer may want more: lengthy details on how each
location is used, which parts of the system use these locations, and so
on. Time and space don't permit such detail.
The maps are intended to be fairly complete. Those who want more detail
may find them cryptic; but at least each location will be associated with a
type of activity. Different machines may be compared by checking their
respective maps. In some cases, programs may be converted with their
use, since they will help to find the corresponding memory location in the
target machine.
When you see a reference to a POKE or PEEK location— in this book or
from other sources — check it in these maps. They will help add perspec-
tive.
767
768 MACHINE LANGUAGE FOR COMMODORE MACHINES
"Original ROM" PET
The Great Zero-Page Hunt
Most users help themselves to the high part of the input buffer {$nQAU
to $D05R, which is not used except when long lines of data are inputted.
Most zero-page locations may be copied to another part of memory so
that their original contents can be restored after use. However, the pro-
grammer should take great care in modifying the following locations, which
are critical within the operating system or BASIC: $D3, $05, $yA to
$t7, $7ft to $fl7, $flq, $RE to $ft3, $B7, $C2 to $Dq, $£□ to $EE,
$F5.
Memory Map
Hex
Decimal
Description
■0002
0-
USE jump
□ □03
3
Current I/O -prompt
suppress
□ □□5
5
Cursor control position
□ □□fi-
-oooq
fl-
■q
Integer value (for SYS, GOTO,
and so on)
□□□a-
-005R
10-
-aq
Input buffer
oosa
qo
Search character
□ □5B
Scan-between-quotes flag
□ □5C
Input buffer pointer; number of
subscripts
□ □5D
q3
Default DIM flag
□ □5E
Type: FF= string;
00 = numeric
□ □5F
Type: 80 = integer; 00= floating
point
□oto
Flag: DATA scan; LIST quote;
memory
OOtl
^7
Subscript flag; FNX flag
□ OtE
qfl
□=INPUT; $^D=GET;
$qfl=REaD
□ 0t3
qq
aTN sign/comparison
evaluation flag
D0t4
100
Input flag (suppress output)
OObB-
-0Dt7
101-
-103
Pointers for descriptor stack
APPENDIX C — "ORIGINAL ROM" PET
769
Hex
Decimal
Description
□ □tfl-
□ □7D
lOA
-HE
Descriptor stack (temporary
strings)
□ □71-
□ □7^
113
-lit
Utility pointer area
□ □75-
□ □7fl
117
-lE^
Product area for multiplication
□ □7ft-
□ □7B
152
-1E3
Pointer: start-of-BASIC
□ □7C-
□ D7D
1E<
-1E5
Pointer: start-of-variables
D07E-
□ D7F
lEfc
-1E7
Pointer: start-of-arrays
□□ao-
□ □fll
lEfl
-lER
Pointer: end-of-arrays
□ □flE-
□ □fl3
13^
-131
Pointer: string-storage (moving
down)
DU&A-
□□as
13E
-133
Utility string pointer
□ □flb-
□ □fl7
13^
-135
Pointer: iimit-of-memory
□ □flfl-
□ □flq
13t
-137
Current BASIC line number
□ □flft-
□ □flB
13fl
-13^1
Previous BASIC line number
□ □flC-
□ DflD
lAU
-lAl
Pointer:BASIC statement for
CONT
□ □flE-
□ OflF
IAS
-1^3
Current DftTA line number
□ □RD-
□oni
lAA
-IAS
Current DftTR address
□ □■=15-
□ 0R3
lAk
-IA7
Input vector
□ □R<-
□ □^5
1A&
-lAR
Current variable name
□ □Rb-
□ □^7
15^
-151
Current variable address
□ □Rfl-
□□qq
15E
-153
Variable pointer for FOR/NEXT
□ □Rft-
□ □•=16
ISA
-155
Y-save; op-save; BASIC
pointer save
□ □RC
15t
Comparison symbol
accumulator
□ □HD-
□ □ftE
157
-IbE
Miscellaneous worl< area,
pointers, and so on
□ □aa-
□ □ft5
lt3
-lti5
Jump vector for functions
□ □Rfc-
□ □AF
Itt
-175
Miscellaneous numeric work
area
□ □BQ
17t
Accum#1 : exponent
□ □Bl-
□ □B-^
177
-IfiD
Accum#1 : mantissa
□ □B5
lai
Accum#1 :sign
□ □Bt
IflE
Series evaluation constant
pointer
□ □B7
lfi3
Accum#1 hi-order (overflow)
□ □Bfl-
□ □BD
Ifl^
-laq
Accum#2: exponent, and so on
□ □BE
IRQ
Sign comparison, Acc#1 versus
#2
□ DBF
IRl
Accum#1 lo-order (rounding)
170
MACHINE LANGUAGE FOR COMMODORE MACHINES
Hex
Decimal
Description
n n o n
□ □cu-
n n r» 1
UUL Ji
1 n 3
r^oocatto Hi iffor lonnth/QOriPQ
Odoocllc UUiici lof ly u i/oci ICO
poinicr
rl n !3
n n "n Q
3 1 "7
PHRfZPT CI iHrni itin^' npt
DMOIw v/lidlCIUld
n nr" n
U uL,il
3 n 1
3 n 3
•dud
RAmO nnintpr fwithin
D/^WIVy L/UII ltd ^VVIll III 1
CI ihmi itinp^
n n T\
□ UDA-
D 1 A
c Jju-
3 3 3
■ddd
DanHAm niimhpr qppH
riOllvJUllI IIUIIIUCI
n riT^ n
□ Ut U-
n ni? 1
-UUti Jj
— — -
— I — If—
-Ed5
Pnintor trt cr^rppn linP
rUIMLwl i\J Owl coll III IC
□ DEE
ddh
D/\oitinn f\4 it'e/^r f\n Qk\m/A lino
rOoiiion OT cursor on auuvc iiiic
UUhd-
dd r-
3 3 A
-ddO
1 ltilit\/ nnintpr* tsnp cprnll
^iiiiiy |JUiiiLd< ia\jxSf ouivjii
n m? c
-UU£ib
— 1 — 1 n
3 3 n
-ddU
Tano pnH flHHrPcc/pnrI nf
1 dUC? Cl lU dUUI COO/\71 lU KJl
curr6ni progrdiii
UUii r -
-U U£i □
d31-
3 3 3
-ddd
Tanp timinn pnnctantc
1 atJC? iiiiiiiiM loicii lio
1 ap6 UUTTci CndrdOLci
□ □£A
LJiroOL/|jiuyidiiiiiicu uuioui.
U — UliCLfL
n n "CI o
□ □EB
3 c
Tana rpaH timor 1 pnahlpH
1 d|Jc/ icdU III MCI 1 CI iduicu
POT rpopiv/pH frnm tanp
u^v^ 1 1 coci vcu 1 1 \ji 1 1
□ □ED
537
ncdU oiididoiCi cnui
n n "CI T3
□ □EE
3 '3 A
C 3 □
iNurnucr oi uiidrdoicio iii iiic
namp
1 Idll IC
n n "CI xi
□ □Er
3 '3 □
wUiicilL illc lUyiOdi dUUICoo
n m? n
3 /■ n
U
r^iirrpnt filp ^^c-nndfirM f)HrlrpQC
ouiiciii IIIC ocwWi lucii y auui coo
n n 1? "1
r^i irront fMp Hp\/ir^P niimHpr
OUllClll Illc UCVIUC llUillUCI
n n xi ^
□ □Ed
3 /■ 3
Line mdryin
n mr'3
-UUr 'I
-EAA
Pointpr* ctart nf tanp huffpr
r wii iici • oicii I v^i ici|^c uuiici
□ □F5
Line where cursor lives
□ □Ft
3 /■ L
dH b
Last l<ey/checl<sum/
nnic^dtanpm ic
illlouclldl icUUo
□ □rr-
-UUro
3 X "5
d^ r-
3 ^ A
-CM Q
1 ape Slail aauicSS
ULI f H-
-uur ft
3 /■ a
3 c n
Pila noma nnintor
nic ndiTiu puiiUci
UUr D
3 C 1
dbil
Miimhpr nf TNc:7PTc
iNuriiUci ui XLNoricxo
ni itctanHinn
uuioidi luii ly
UUc L
\A/rita cHift \A/nrH/rpaH oHarantor
VVillc oiliil wuiU/icdU uiididuici
ODFD
553
in
Tape blocl<s remaining to write/
read
□ GFE
Serial word buffer
□ !□□•
-□IDft
E5b
-Ett
STE$ work area
□
-□13E
E5t
-31fl
Tape read error log
□ !□□
-□IFF
E5b
-511
Processor stacl<
APPENDIX C — "ORIGINAL ROM" PET
171
Hex
Decimal
Description
□ 200-
LJ L. I_l LJ
.npnp
LJ ^ LJ ^
biic-
-bid
jury ciocK Tor x ± ana i j. *
U C U J
515
wnicn Key aown. ebb = no K6y
U C U H
bib
onin Key. i it aepressed
n?rm-
U C LI
U C U D
3 Jj r -
CIA
-d Jj o
v/orreciion ciock
DED7-
LJ l_ LJ LJ
CIO
c 3 n
oassciie siaius, flfjj ana ifc
Ll L_ LJ 1
5E1
ixeyswiicn ciR. oivc ana
RVS flags
□ EDA
bcc
Timing constant for tape
u c u o
C D "3
bed
Loaa = u, verity = i
U t_ LJ V_>
c 3 /■
b c'l
OlalUS WOru o 1
□ POD
LJ L- LJ U
CPC
-] C P
iNurnuer oi criaraciers in
Uoi/Kna rH Kiiffar
l\cyUUcliU UUIfci
□ 2QE
C P L
P C b
oorccii reverse riay
□ 20F-
LJ l_ ^ Ul
be r-
c 3 r
■bd b
rxeyuuarci inpui uurrer
□ 2iq_
LJ i_ jj n
bd r-
Q
■bdo
± £v veclur
npi.R-
U C JJ o
U C Ji L«
c n a
bdT-
c /" n
■b A U
Unix interrupt vector
npl.n
U C JJ L/
c y 1
b^ 1
■etc output, c b b = cnaracter
penoing
U C JJ Ij
c /* □
bs c
Cn^.nf lino fm* inm it i^/^in'f^v
cna-oT-une-Tor-inpui pointer
nppri-
u c c u
-flPPI.
U C C JJ
eye
•b^b
L/Ursor log ^row, coiunnn)
nppp
u c c c
b A b
icct output Dutter
U C C J
b'l 7
f\ey image
C /* A
b'l Q
u — tiasn cursor
U C C 3
C /* Q
bH "i
oursor liming couniaown
nppL
u c c tl
CCD
P p u
onciracier unaer cursor
□ P27
C C 1
b b 1
ouioUi III uiiiiiv pi ictoe
U C C G
c C J
b d c
ri u 1 receivea irom tape
U l_ ^ 1
LJ ^ *-f JJ
c c *□
bbd —
C "7 "7
■b r r
Q/^roon lino \A/ron fraHIa
ooreeii iiiie wrap lauie
npz; p_
LJ L *-l t
U C H IJ
C "7 A
b r □ —
C A-7
bo r
me lugiuai aourebs lauie
LJ L. *-1
LJ L^ J
C A A
b Q —
e a "7
•bn f
■ lie ueviue iiuiiiuei lauie
u c ^ □
u c D r
CCA
(L n "7
bU r
me secondary auoress laoie
u c □ u
L n A
b U u
Inm it fminn o/^fAAn/fmin
inpul irom soreen/irom
QEkl
X save
IHow many open files
□ Et3
til
Input device, normally □
□ Et4
fclE
Output CMD device, normally 3
□ Eb5
tl3
Tape character parity
□ Ett
tl4
Byte-received flag
□ Etfl-
□ EbR
fcl5-
File name pointer; counter
772
MACHINE LANGUAGE FOR COMMODORE MACHINES
Hex
Decimal
Description
□ EtF
DE7D
□ 273
DE75
□57t-D277
D57fl
□ 27q
□ 27R-
□ 33a-
□ 3FA-
□ ^DD-
flDDO-
CODD-
-□33q
-□3Fq
-□3FB
-7FFF
-fl3E7
-E7Ffl
t53
tE7
b3D-t31
b3E
t33
t34-fl25
flab-lD17
IDlfl-lDlR
1054-3E7fc7
3E7tfl-337b7
^qi5E-5q3fl<
EfllD-Eai3 ER^Dfl-Sq^ll
EflE^-Efl53 5S4E^-5R4E7
Efl^D-Efl^F 5^-^5^-5^471
FDDD-FFFF fcl44D-t5535
Serial bit count
Cycle counter
Tape writer countdown
Tape buffer pointers, #1 and
#E
Write leader count; read pass
1/2
Write new byte; read error flag
Write start bit; read bit
sequence error
Error log pointers, pass 1/2
□ = scan/1-1 5 = count/
$4^ = load/$aD=end
Write leader lengtfi; read
checksum
Tape#l input buffer
Tape#E input buffer
Monitor extension vector
Available RAM including
expansion
Screen RAM memory
BASIC ROM; part of kernal
ROM
PI A 1 (6520)-keyboard
interface
PIA E (6520)-iEEE interface
VIA (6522)-Miscellaneous
interface, timers
Kernal ROM routines.
PIA and VIA charts are the same as shown for Upgrade/4.0 units.
UPGRADE and BASIC 4.0 Systems
Tlie Great Zero-Page Hunt
Zero-page locations are tough to find in these areas. Locations $1F to
$E7, $<Bto $5^, and $54 to $5D are work areas available for tem-
porary use. If tape is not being read or written, addresses $B1 to $C3
are available.
APPENDIX C — UPGRADE AND BASIC 4.0 SYSTEMS
173
Most zero-page locations may be copied to anotlier part of memory so
that their original contents can be restored after use. The programmer
should take great care, however, in modifying the following locations, which
are critical within the operating system of BASIC: $10, $13 to $15,
$Eato$3 5, $37, $5Dto$51, $E.5, $7Dto$fl7, $flDto$BD, $CA
to $FR.
Memory Map
Where Upgrade ROM differs from 4.0, an asterisk (*) is shown and the 4.0
value is given. There are some differences in usage between the 40- and
80-column machines.
Hex
Decimal
uescripuon
□ □□0-
-□□□E
0-
-E
USE jump
□ □□3
3
Search character
Scan-between-quotes flag
0DD5
5
Input buffer pointer; number of
subscripts
□ □□t
Default DIM flag
00D7
7
Type: FF = string; □□ = numeric
□ □□fi
a
Type: flO = integer;
00 = floating point
□ □□S
Flag: DRTfl scan; LIST quote;
memory
□ □□A
10
Subscript flag; FNX flag
□ □OB
11
D=INPUT; $40=GET;
$qfl=REaD
OODC
IE
ATN sign/comparison
evaluation flag
□ □OD-
■□□OF
13-
■15
"Disk status DS$ descriptor
□ DID
It
*Current I/O device for prompt-
suppress
DOll-
■□□IE
17-
■Ifl
Integer value (for SYS, GOTO,
and so on)
□ □13-
•0015
iq-
■El
Pointers for descriptor stack
□ □It-
•OOIE
EE-
■3D
Descriptor stack (temporary
strings)
□ □IF-
•OOEE
31-
■3A
Utility pointer area
□ □53-
■00E7
35-
■3q
Product area for multiplication
□ □Efl-
■OOEq
^0-
•41
Pointer: start-of-BASIC
□□aa-
ODEB
4E-
■A3
Pointer: start-of-variables
□ □EC-
OOED
■AS
Pointer: start-of-arrays
174
MACHINE LANGUAGE FOR COMMODORE MACHINES
Hex
Decimal
Description
□ □EE-
□ □EF
Af=-
47
Pointer: end-of-arrays
□ □3D-
□ □31
A&-
4q
Pointer: string-storage (moving
down)
□ □3a-
□ □33
50-
51
Utility string pointer
□ □34-
□ □35
5E-
53
Pointer: limit-of-memory
□ □3b-
■□□37
54-
55
Current BASIC line number
□ □3fl-
■□□3q
5b-
-57
Previous BASIC line number
□□3a-
-□□3B
5fl-
-5q
Pointer: BASIC statement for
CONT
□ □3C-
-□□3D
fcO-
-bl
Current DRTfi line number
□ □3E-
-□□3F
fcE-
-b3
Current DATA address
□ □<□-
-DQAl
b4-
-b5
Input vector
-□□43
bb-
-b7
Current variable name
nuAh-
■QUA7
7^-
-71
Variable pointer for FOR/NEXT
-□□4H
7E-
-73
Y-save; op -save; BASIC
pointer save
UQAk
74
Comparison symbol
accumulator
QQAB-
-□□5^
75-
-flD
Miscellaneous work area,
pointers, and so on
□ □51-
-□□53
fil-
-fl3
Jump vector for functions
□ □5-^-
-□□5D
fl4-
-=13
Miscellaneous numehc work
area
□ □5E
q4
Accum#1 : exponent
□ □5F-
-□□tE
q5-
-qa
Accum#1 : mantissa
□ □fc3
Accum#1 : sign
QULA
1^^
Series evaluation constant
pointer
□ □b5
1^1
Accum#1 hi-order (overflow)
□ Otb-
-□□tB
l^E-
-1D7
Accum#2: exponent, and so on
□□tc
l^fl
Sign comparison, Acc#1 versus
#2
□ OtD
l^b
Accum#1 lo-order (rounding)
□ □tE-
-□□tF
ll^-
-111
Cassette buffer length/series
pointer
□ □?□■
-□□fl7
llE
-135
CHRGET subroutine; get
BASIC character
□ □77
-□□7a
IIR
-la^
BASIC pointer (within
subroutine)
□ □fifl
-□□flC
13b
-14D
Random number seed
□ □flD
-□□flF
141
-143
Jiffy clock for TI and TI$
APPENDIX C — UPGRADE AND BASIC 4.0 SYSTEMS
175
Hex
Decimal
Description
□oqo-
■□□qi
lAA-
■IAS
IRQ vector
■□□q3
■1A7
BRK interrupt vector
□oq^-
■□□qs
■i^q
NMI interrupt vector
□□qt
15^
Status word ST
□ □q?
151
Wliicli key down: 25 5 = no key
□□qa
155
Sliift key: 1 if depressed
□□qq-
□oqa
153-
■ISA
Correction clock
□□qB
155
Keyswitch PI a: STOP and
RVS flags
□oqc
15t
Timing constant for tape
ooqD
157
Load = D; verify =1
□□qE
15fl
Number of characters in
keyboard buffer
□ □qp
15q
Screen reverse flag
□□ao
ItQ
IEEE output: E55 = character
pending
□ OAl
Itl
End-of-line-for-input pointer
□ □R3-
lt3-
11.A
Cursor log (row, column)
ooas
lt5
IEEE output buffer
Itt
Key image
□□a?
It?
□ = flash cursor
□ □ftfl
Ibfl
Cursor timing countdown
□□aq
iE,q
Character under cursor
□□aa
17^
Cursor in blink phase
□ □aB
171
EOT received from tape
□ □ac
173
Input from screen/from
keyboard
□ □aD
173
X save
DoaE
17^
How many open files
ooaF
175
Input device, normally □
□ OBQ
l?b
Output CMD device, normally 3
DDBl
177
Tape character parity
□ □BE
17fl
Byte-received flag
□ □B3
i7q
Logical address temporary save
UUBA
la^
Tape buffer character; MLM
command
□ □B5
lai
File name pointer; MLM flag;
counter
□ □B7
ia3
Serial bit count
□□Bq
IflS
Cycle counter
□ □Ba
lat
Tape writer countdown
776
MACHINE LANGUAGE FOR COMMODORE MACHINES
Hex
Decimal
Description
□ QBB-
□ □BC
lfl7-
Iflfl
Tape buffer pointers, #1 and
#E
□ □BD
laq
Write leader count; read pass
1/2
□ QBE
Write new byte; read error flag
□ DBF
Write start bit; read bit
sequence error
OOCD-
□ □CI
IRE-
1R3
Error log pointers, pass 1/2
□ □C2
□ = scan/1 - 15 = count/
$^^ = load/$fl^ = end
□ QC3
1R5
Write leader length; read
checksum
UUCA-
□ □C5
IRt-
•1R7
Pointer to screen line
QDCb
Position of cursor on above line
unci-
LJ LJ 1
■□□Cfl
-E^D
Utility pointer: tape, scroll
ODCR-
-□□CA
l_ LJ -U
-E^E
Tape end address/end of
current program
□ QCB-
LJ LJ v_« LJ
-□□CC
EU3-
-E^4
Tape timing constants
nocD
Ul LJ Vrf !>/
ED5
□ = direct cursor; else
programmed
□ OCE
^□ti
Tape read timer 1 enabled
□ □CF
^□7
EOT received from tape
ODDD
EDfl
Read character error
□ ODl
^□'l
Number of characters in file
name
□ DDE
EID
Current file logical address
□ □D3
Ell
Current file secondary address
QUDA
ElE
Current file device number
□ □D5
E13
Right-hand window or line
margin
□ DDt-
-□□D7
E14-
-E15
Pointer: start of tape buffer
ODDfl
Elt
Line'where cursor lives
E17
Last key/checksum/
miscellaneous
□□Da
-□□DB
Elfl
-EIR
File name pointer
□ □DC
EE^
Number of INSERTS
outstanding
□ □DD
EEl
Write shift word/read character
□ □DE
EEE
in
Tape blocks remaining to write/
read
APPENDIX C — UPGRADE AND BASIC 4.0 SYSTEMS
t77
Hex
Decimal
n n T> "0
□ □DF
SE3
□ □ED-
□ □Ffl
-EAQ
□ □ED-
□ □El
EE4-
-EES
□ □ES
EEb
□ □E3
EE7
□ □E<
EEfl
□ □E5
P P Q
n n "CI r
E3^
DQE7
E31
□ □Efl
E3E
OOEq-
□ □Eft
E33-
-E3^
□ OEB-
□ □EC
E35-
-E3t
ODFS-
□ □FR
-E5^
□ □FB-
□ □FC
E51-
-E5E
□ □FD-
□ □FE
E53
-ESA
□ lOD-
□ l^ft
E5t
-Efct
OlDD-
□ 13E
E5t
-31fl
□
□ IFF
E5t
-511
QEQD-
□ E5D
51E
-BRE
□ E51-
-□E5ft
5^3
-^□E
□ E5B-
■nEhA
bD3
-tlE
□ Eb5-
•□EbE
bl3
-tEE
□ EtF-
■□S7fl
bE3
-fc3E
0E7R-
-□33q
t3<
-flE5
033a-
■□3Fq
fiEt
-1^17
Q33ft-
■□3fi^
fiEt
03Eq
!□□!
03Ea
l^^E
03EB
1^^3
□ 3EC
inuA
□ 3ED
03EE
IDDb
03EE-
■□3F7
-1D15
□ 3EF
1^D7
□ 3FD-
l^Dfi
-1D17
Q3Fa-
□ 3FB
l^lfl
-i^iq
Description
Serial word buffer
(40-column) Screen line wrap
table
*(80-column) Top, bottom of
window
*(80-column) Left window
margin
*(80-column) Limit of keyboard
buffer
*(80-column) Key repeat flag
*(80-co!umn) Repeat countdown
*(80-column) New key marker
*(80-column) Chime time
*{80-column) HOME count
*(80-column) Input vector
*(80-column) Output vector
Cassette status, #1 and #E
MLM pointer/tape start address
MLM, DOS pointer,
miscellaneous
STR$ work area, MLM work
Tape read error log
Processor stack
MLM work area; input buffer
File logical address table
File device number table
File secondary address table
Keyboard input buffer
Tape#l input buffer
Tape#E input buffer
*DOS work area
(Fat 40) New key marker
(Fat 40) Key repeat countdown
(Fat 40) Keyboard buffer limit
(Fat 40) Chime time
(Fat 40) Decisecond timer
(Fat 40) Key repeat flag
(80-column) Tab stop table
(Fat 40) Tab work value
(Fat 40) Tab stops
Monitor extension vector
778 MACHINE LANGUAGE FOR COMMODORE MACHINES
Hex Decimal
□3FC
04DD-7FFF in2A-327h7
flDDD-a3E7 3E7tfi-337fc7
flDDD-fi7CF 3E7t,a-3^7L7
qaOD-aFFF 3bfit<-^5D55
BDDD-E7FF ^5D5t.-5q3Rl
Efll0-Efll3 BH^Dfl-SR^ll
EflEn-Efl53 5q'^E4-5R^27
Efl^D-Efl^F 5R45fc-5q^71
EflflD-Eflfll BSBED-B^SEl
FDDO-FFFF tl4<D-t.5535
Description
*IEEE timeout defeat
Available RAM including
expansion
(40-column) Video RRM
*(80-column) Video RAM
Available ROM expansion area
BASIC ROM, part of kernal
PI A l-l<eyboard I/O
PI A E-IEEE-488 I/O
VIA-l/0 and timers
(80-column and Fat 40) CRT
controller
Kernal ROM
6520
E810
Diag Sens/
Uncrash
EOl in
Tape Switch Sense
#1 #2
Keytjoard Row Select
59408
E811
Tape#1 In
Latch
(Screen Blank— Orig
ROM) EOl Out
DDRA
Access
Tape#1 Input L
Control
59409
E812
Keyboard Input for selected row
59410
E813
Retrace
Latch
Cassette#1 Motor
Output
DDRB
Access
Retrace Interrupt
Control
59411
Figure C.I
PIA 1 chart
6520
E820
IEEE-488 Input
59424
E821
ATN Int
NDAC Out
DDRA
Access
ATN Int Control
59425
E822
IEEE-488 Output
59426
E823
SRQ Int
DAV Out
DDRB
Access
SQR Int Control
59427
Hgure C.2
PIA 2 chart
APPENDIX C — CBM 8032 AND FAT-40
179
6522
Retrace
In
Tape#2
Motor
Tape
Output
NRFD
Out
E840
DAVIn
NRFD In
ATN Out
NDAC In
59456
E841
Unused (See E84F)
59457
E842
Data Direction Re
g
ster B (for E840)
59458
E843
Data Direction Re
g
ster A (for E84F)
59459
E844
E845
Timer 1
59460
59461
E846
Timer 1 Latch
59462
59463
E848
E849
Timer 2
59464
59465
E84A
Shift Register (unused)
59466
E84B
T1 Control
T2Cont
Shift Register Control
Latch Controls
PB PA
59467
E84C
CB2 (PUP) Control
CB1 CntI
Tape#2
CA2 Control
GraphicsAText Mode
CA1
(PUP)
Control
59468
E84D
E84E
Irq Stats
Int EnabI
Timer
1
Int
Timer
2
Int
CB1
Tape#2
Int
CB2
(PUB)
Int
SR
Unused
CA1
(PUP)
Int
CA2
G/T Mode
unused. .
59469
59470
E846F
Parallel User Port Data Re(
y
ster PA
59471
Figure C.3
VIA chart
CBM 8032 and FAT-40
6545 CRT Controller
NOTES: 1 . Registers are write-only.
2. Avoid extreme changes in Register 0. CRT damage could
result.
3. Register vi/ill adjust scan to allow interfacing to external
monitor.
4. Register 12, Bit 4, will "invert" the video signal.
5. Register 12, Bit 5, switches to an alternate character set. The
character set is not implemented on most machines except
Super-PET.
780
MACHINE LANGUAGE FOR COMMODORE MACHINES
$E880
59520
$E881 TYPICAL VALUES
59521 (DECIMAL)
i TEXT GRAPHICS
HORIZONTAL TOTAL
1
HOR. CHAR. DISPLAYED
2
H. SYNC POSITION
3
V SYNC WIDTH h
4
X VERTICAL TOTAL
5
VERT. TOT. ADJUST
6
VERTICAL DISPLAYED
7
VERT. SYNC POSITION
8
MODE
9
SCAN LINES
10
CURSOR START (UNUSED) —
11
— (
12
X
C
R DISPLAY
13
ADDRESS
49
40
41
15
32
3
25
29
9
16
49
40
41
15
40
5
25
33
7
16
NOTES: 1. REGISTERS ARE WRITE-ONLY
2. AVOID EXTREME CHANGES IN
REGISTER, OR CRT DAMAGE
COULD RESULT
3. REGISTER WILL ADJUST SCAN
TO ALLOW INTERFACING TO
EXTERNAL MONITOR
4. REGISTER 12, BIT 4, WILL "INVERT"
THE VIDEO SIGNAL.
5. REGISTER 1 2, BIT 5, SWITCHES TO
AN ALTERNATE CHARACTER SET.
THE CHARACTER SET IS NOT
IMPLEMENTED ON MOST MACHINES
EXCEPT SUPER-PET.
Figure C.4
APPENDIX C — VIC 20
181
VIC-20
The Great Zero-Page Hunt
Locations $FC to $FF are available. Locations $52 to $^E to
$53, and $5? to $tD are work areas available for temporary use.
Most zero-page locations may be copied to another part of memory so
that their original contents can be restored after use. However, the pro-
grammer should take great care in modifying the following locations, which
are critical within the operating system or BASIC: $1B, $lt to $lfi,
$2Bto $3a, $3a, $53 to $54, $ta, $73 to $flA, $qDto $Rft, $aD
to $ftE, $Ba to $Bft, $C5 to $YA.
Memory Map
Dpoimsl
Descriotion
ODDD-
•□□□2
USR jump
□ Q03-
■DQQA
3-4
Float-fixed vector
□ □05-
■OODh
5-t
Fixed-float vector
□ □□?
7
Search character
□□□a
a
Scan-quotes flag
□ □□q
q
TfiB column save
□ □□A
10
D = LOaD, 1 = VERIFY
□ □□B
11
Input buffer pointer/number of
subscripts
□ □□C
12
Default DIM flag
□ □□D
13
Type: FF = string; 00 = numeric
□ □OE
14
Type: a = integer;
O0=floating point
□ □OF
15
DATA scan/LIST quote/
memory flag
OOID
It
Subscript/FNx flag
0011
17
D=INPUT; $4D=GET;
$qa=REftD
ooie
la
ATN sign/Comparison
evaluation flag
□ □13
iq
Current I/O prompt flag
□ 014-
-□□15
EO-El
Integer value
OOlt
EE
Pointer: temporary string stack
□ □17-
-□oia
E3-E4
Last temporary string vector
182 MACHINE LANGUAGE FOR COMMODORE MACHINES
Hex
Decimal
Description
U LJ JJ n
□ □31
pp
Stack for temporary strings
nn??-
u u c ^
□ 035
LJ LJ l_ _J
J H —
P7
J r
Utility pointer area
U U C D
U U C £l
p □ —
Z P
Product area for multiDlication
nnPR_
UUCD —
nnpr
u u c ^
'i P —
Pointer- start-of-BASIC
n n pr»
U U C£i
'I P —
Z L
Polnfpr' ^tart-of-variables
uucr —
n rr^ n
r —
Z A
Pnintpr* ^tart-of-arravs
nmi.
U U J Ji —
Z Q_
P u
Pointpr' end-of-arravs
r wii iivi ■ wi lu WI Mi 1 uy w
j jj
CP
Pointer* strino-storaoe fmovina
1 Wii i Iwi ■ wll II ijg W WI V 111 I w VII
down)
UUIj j
-t;4
Utiiitv strina Dointer
^^IIIILV Wll II M\A MWll IWI
U U J f
.nrr^ ft
p p
D □
Pointer* limit-of-memorv
1 ^/ll l^^^l ■ llllllfe \#l 1 1 l\^l I V
U U J " —
.n m B
'U UP n
^ u
Ciirrpnt BASIC line number
1 1 wl 1 1 LJt\^Jt\^ III 1 w 1 IVII 1 ll<^ wl
D —
-t,n
Previous BASIC line number
1 1 V I^^U W 1 III ■ 1 Ml 1 Ih^^^l
UU J LI
a Jj
□ ^
Pointer: BASIC statement for
CONT
DD3F-
■□□4D
t4
Current DATA line number
□ □41-
■□□42
t5-
Current D&TA address
nnA3-
□ □44
b7-
Input vector
□ □45-
■□□4t
EjR-
•7D
Current variable name
□ □47-
-□□4fl
71-
■7E
Current variable address
□ □4R-
■□□4R
73-
■74
Variable pointer for FOR/NEXT
□ □4B-
•□□4C
75-
■7t
Y-save; op-save; BASIC
pointer save
□ □4D
77
Comparison symbol
accumulator
□ □4E-
■□□53
7fl-
■fl3
Miscellaneous work area
IVIiW\^WIIUI IWWUW VWI Ix Vtl Wwi)
Dointers and so on
□ □54-
-□□5b
A4-
l_J *1
U □
Jumo vector for functions
UUI 1 ill/ V WwVWI 1 WI i Ul i w&i Wi i w
□ □57-
fl7-
Miscellanenufi numeric work
iViiOW^OiiCli iwWUw 1 iUI 1 Iwl Iw VVWl l\
area
□ □bl
^7
Accum#li' exDonent
□ □tE-
-□□fc5
Sfl-
-IDl
Accum#l: mantissa
□ □bb
l^E
Accum#l: sign
□ □fc7
1^3
Series evaluation constant
pointer
□ □tfi
1^4
Accum#1 hi-order (overflow)
□□tq-
-□□tE
1^5-
-ll^
Accum#2: exponent, and so on
□ □tF
111
Sign comparison, Acc#l versus
#E
□ □7D
112
Accum#l lo-order (rounding)
APPENDIX C — VIC 20
183
Hex
Decimal
Description
□ 071-
-□□72
113-
-IK
Cassette buffer length/series
pointer
□ D73-
-□□aa
115-
-13a
CHRGET subroutine; get
BASIC character
□ □?&■
-□□7B
15E-
-1E3
BASIC pointer (within
subroutine)
□ □SB-
-□□aF
13q-
-1A3
END seed value
□ □SO
Status word ST
DOHl
IAS
Keyswitch PI a: STOP and
EVS flags
n n n — 1
Timing constant for tape
□ □R3
1A7
Load = D; verify =1
n n n /■
iAe>
Serial output: deferred character
00H5
flag
Serial deferred character
ISD
Tape EOT received
□ □s?
151
Register save
□ □sa
155
How many open files
153
Input device, normally □
□ORa
154
Output CMD device, normally 3
OOHB
155
Tape character parity
ODRC
15t
Byte-received flag
OORD
157
Direct = $ a □/RUN = □ output
control
n PI mn
□ □HE
15a
Tape pass 1 error log/character
buffer
□ □RF
15q
Tape pass E error log corrected
OOAD-
-□□as
ItD-
-ItE
Jiffy Clock HML
□ OAB
lt.3
Serial bit count/EOI flag
lt4
Cycle count
n n 7\ c
lb5
Countdown, tape write/bit count
□ □At
ILt
Tape buffer pointer
□ □ft?
lti7
Tape write leader count/read
□□aa
pass/inbit
ita
Tape write new byte/read error/
inbit count
□□as
itq
Write start bit/read bit error/stbit
□□aa
17^
Tape Scan;Cnt;Load;End/byte
□□an
assembly
171
Write lead length/read
checksum/parity
184 MACHINE LANGUAGE FOR COMMODORE MACHINES
Hex Decimal Description
□□ac-
□ □AD
17E-
173
Pointer: tape buffer, scrolling
□ □ftE-
□ □fiF
174-
175
Tape end address/end of
program
□ □BD-
□ □Bl
17t.-
17?
Tape timing constants
□ □BE-
□ □B3
17fl-
l?q
Pointer: start of tape buffer
DUBA
1 =tape timer enabled; bit count
□ □B5
lai
Tape E0T/RS232 next bit to
send
□ □Bt
IflE
Read character error/outbyte
buffer
DOB?
lfl3
Number of characters in file
name
□ □Bfi
l&A
Current logical file
DOBq
135
Current secondary address
□ □BR
l&h
Current device
□ □BB-
■□□BC
lfl7-
■Iflfl
Pointer to file name
□ DBD
iflq
Write shift word/read input
char
□ □BE
mn
Number of blocks remaining to
write/read
□ □BF
iHi
Serial word buffer
□ OCO
IRE
Tape motor interlock
□ OCl-
-□□CE
1^3-
■iq<
I/O start address
□ □C3-
■nucA
IRS-
-iqt
Kernal setup pointer
□ □C5
1^7
Last key pressed
□act
iqfl
Number of characters in
keyboard buffer
□ DC?
iqq
Screen reverse flag
ODCfi
EDD
End-of-line for input pointer
oocq-
-□□ca
EDl-
-EDE
Input cursor log (row, column)
□ □CB
E^3
Which key: kA if no key
□occ
BUA
□ = flash cursor
□ □CD
BOS
Cursor timing countdown
□ □CE
EDt
Character under cursor
□ □CF
ED?
Cursor in blink phase
□ □D^
EDfi
Input from screen/from
keyboard
□ □Dl-
-□□DE
EDq-
-El^
Pointer to screen line
□ □D3
Ell
Position of cursor on above line
APPENDIX C — VIC 20
185
Hex
Decimal
Description
ElE
□ = direct cursor; else
programmed
□ DDE
E13
Current screen line length
□ □Dt
El<
Row where cursor lives
□ □D7
S15
Last inkey/checksum/buffer
□ □Dfl
Elt
Number of INSERTS
outstanding
□ DDR-
■□□F^
E17-
E^^
Screen link table
□ □Fl
E^l
Dummy screen link
OGFE
E4E
Screen row marker
D0F3-
■QDF^
E<3-
•E<<
Screen color pointer
□ 0F5-
■□□Ffc
E45-
■E^t
Keyboard pointer
□ QF7-
■□□Ffi
E^7-
■E^a
RS-232 Rev pntr
OOFq-
■□□Fa
E^q-
E5D
RS-232 Tx pntr
□ □FF-
■oina
E5b-
■Etfc
Floating to ASCII work area
□
^□3E
E5t-
•3ia
Tape error log
□ lOD-
□ IFF
E5t-
•511
Processor stack area
□ 5Qa-
□ EBfl
51E-
BASIC input buffer
□ ESR-
-□EtE
^□1-
-tl^
Logical file table
□ Et3-
■□Etc
tll-
-tE^
Device number table
□ 2tD-
-□E7fc
tEl-
-fc3^
Secondary address table
□ 577-
-□Efl^
t31-
-yAU
Keyboard buffer
□ 561-
-□EflE
hAl-
-t<E
Start of BASIC memory
□ 5fi3-
-□Efl4
t43-
Top of BASIC memory
□ EflS
t45
Serial bus timeout flag
□eat
Current color code
□ Efl7
t<7
Color under cursor
□ Eflfl
Screen memory page
□ Eflq
t^q
Maximum size of keyboard
buffer
□ Efla
Repeat all keys
□ EflB
t51
Repeat speed counter
□ EfiC
b5E
Repeat delay counter
□ EflD
t53
Keyboard shift/control flag
□ EflE
Last shift pattern
□ EflF-
-□Eq^
t55-
Keyboard table setup pointer
□Eqi
fc57
Keymode (Kattacanna)
□ EqE
tsa
□ = scroll enable
□Eq3
fcsq
RS-232 chip control
□Eq^
RS-232 chip command
186 MACHINE LANGUAGE FOR COMMODORE MACHINES
Hex
Decimal
Description
0515-
■□Eqt
ttl-
-btE
Bit timing
RS-232 status
hhA
Number of bits to send
□2qq-
-□E^fi
tt5
RS-232 speed/code
□ BRB
tt7
RS-232 receive pointer
DE^C
RS-232 input pointer
□ ERD
ttq
RS-232 transmit pointer
□ ERE
t7D
RS-232 output pointer
□ ERF-
-□Eao
fc71-
-fc7E
IRQ save during tape i/0
□ 3D0-
-03D1
7bfl-
-7tq
Error message link
D3DS-
-□3D3
77^-
-771
BASIC warm start iinic
-03D5
77E-
-773
Cruncli BASIC tokens link
□ 3Dt-
-□3D7
774-
-775
Print tokens link
□ 3Dfl-
-□3Dq
77t-
-777
Start new BASIC code link
□ 3Da-
-□3DB
77fl-
-77q
Get arithmetic element link
□ 3DC
7fi^
SYS A-reg save
□ 3DD
7fll
SYS X-reg save
□ 3DE
7flE
SYS Y-reg save
□ 3DF
7fl3
SYS status reg save
□ 314-
-□315
7flfl-
-7aq
IRQ vector (EftBF)
□ 31t-
-0317
7R^-
-791
Break interrupt vector (FEDE)
□ 31fl-
-□3iq
7qE-
-793
NMI interrupt vector (FEftD)
□3ia-
-□31B
7R4-
-795
OPEN vector (F4Da)
□ 31C-
-□31D
7qt-
-797
CLOSE vector (F34a)
□ 31E-
-□31F
7qfl-
-799
Set-input vector (FEC7)
□ 3ED-
-□3E1
&□□-
-fl^l
Set-output vector (F309)
□ 3EE-
-□3E3
e,OE-
-flD3
Restore I/O vector (F3F3)
U32A-
-□3E5
-fl^5
INPUT vector (FEDE)
□ 3Eb-
-□3E7
&Uh-
-flD7
Output vector (FE7a)
□ 3Efl-
-□3Eq
-fl^9
Test-STOP vector (F77 0)
□ 3EA-
-□3EB
fll^-
-fill
GET vector (F1F5)
□ 3EC-
-□3ED
fllE-
-fll3
Abort I/O vector (F3EF)
03EE-
-□3EF
ai4
-fll5
USR vector (FEDE)
□ 33D-
-□331
filb
-fll7
LOaD link
□ 33E-
-□333
fllfl
-fll9
SaVE link
□ 33C
-□3FB
flEfl
-1019
Cassette buffer
-□FFF
1DS4
-4095
3K RaM expansion area
-IFFF
-fll91
Normal BASIC memory
EDDD
-7FFF
fiiqE
-3E7b7
Memory expansion area
flQDD
-flFFF
3E7tfl
-3tat3
Character bit maps (ROM)
APPENDIX C — VIC 20
187
Hex Decimal Description
qODO-qoOF Btab-^-ataTR video interface chip (6560)
RllD-RlEF 3713t.-37151 VIA (6522) interface-NMI
qiED-qiEF 3715E-371t7 VI R (6522) interface- IRQ
R^DO-qSFF 37flflfl-3fl3q'=1 Alternate color nybble area
qtD0-'=l7FF 3fl4QD-3fl'=111 Main color nybble area
ADDO-BFFF An^hQ-AmSl Plug-in ROM area
CDDD-FFFF 4qi5E-b5535 ROM: BASIC and operating
system
788 MACHINE LANGUAGE FOR COMMODORE MACHINES
VIC 6560 Chip
$9000
Inter-
lace
Left IVIargin ( =
= 5)
36864
$9001
Top Margin ( = 25)
36865
$9002
Scrn Ad
bit 9
# Columns ( =
22)
36866
bItO
# Rows ( = 23)
Double
Char
$9004
Input Raster Value: bits 8-1
36868
$9005
Screen Address
bits 13-10
Character Address
bits 13-10
36869
$9006
$9007
Light Pen Input
Horizontal
Vertical
36870
36871
vpsUUo
$9009
Paddle Inputs
X
Y
36873
$900A
_ ON
Voice 1
36874
$900B
$900C
_ ON
ON
Voice 2 _
Frequency —
Voice 3
36875
36876
$900D
ON
Noise
36877
$900E
Multl-Colour Mode ( = 0)
Sound Amplitude
36878
$900F
Screen Background Color
Foregnd
/Backg
Frame Color
36879
Figure C.5
APPENDIX C — VIC 6522
189
VIC 6522 Usage
$9110
$9111
$9112
$9113
$9114
$9115
$9116
$9117
$9118
$9119
$911 A
$91 1B
$91 1C
$91 ID
$91 IE
$91 IF
DSR
CTS 1
1 DCD*
Rl*
DTP
RTS
Data
In
In 1
1 In
In
out
out
In
_T1-L
T1-H
_T1 Latch L
T1 Latch H
J2-L
T2-H
RS-232 Interface
or, Parallel User Port
Unused — see $91 IF
DDRB (for $9110)
DDRA (for $91 IF)
RS-232 Send Speed;
Tape Write Timing
RS-232 Input timing
Shift Register (*unused)
T1 Control
T2Cnt
Shift Reg Control
PB LE
PA LE
CB2: RS-232 Send
CB1 C
CA2: Tape motor Ctrl
CA1 ai
NMI:
T1
T2
CB1:
RS-232
In
1
CA1:
Restore
button
ATN
out
Tape
sense
Joysticks
Button 1 Left | Down | Up
Serial
Data In
Serial
Clk In
37136
37137
37138
37139
37140
37141
37142
37143
37144
37145
37146
37147
37148
37149
37150
37151
Figure C.6
790 MACHINE LANGUAGE FOR COMMODORE MACHINES
VIC 6522 Usage
$9120
$9121
$9122
$9123
$9124
$9125
$9126
$9127
$9128
$9129
$91 2A
$91 2B
$91 2C
$91 2D
$91 2E
$91 2F
Joystk
Right
1
Tape
Out
Keyboard Row Select
Keyboard Column Input
DDRB (for $9120)
DDRA (for $9121)
T1-L
T1-H
T1-L Latch
T1-H Latch
Cassette Tape Read;
Keyboard & Clock
Interrupt Timing
T2-L
Serial Bus Timing
T2-H
Tape R/W Timing
Shift Register (*Unused)
T1 Control
T2 Ctrl
Shift Register Contrl
PB LE
PALE
Serial Bus Data Out
CB1
ContI
Serial Clock Line out
CA1
ContI
IRQ:
T1
T2
CB1:*
SRQ in
CA1:
Tape in
*Unused: see $9121
Figure C.7
APPENDIX C — COMMODORE 64
191
Commodore 64:
The Great Zero-Page Hunt:
Locations $FC to $FF are available. Locations $EE to $2fl, $<E to
$53, and $57 to $tn are work areas available for temporary use.
Most zero-page locations may be copied to another part of memory so
that their original contents can be restored after use. The programmer
should take great care, however, in modifying the following locations, which
are critical within the operating system or BASIC: $13, $lt to $lfl,
$2Bto $3fl, $3a, $53 to $SA, $tfl, $73 to $flft, $^Dto $qft, $ftO
to $aE, $Bfl to $BA; $C5 to $F4.
Memory Map
Hex
Decimal
Descriotion
□ □□□
□
Chip directional register
n n n 1
□ □□I
1
onip i/u, memory ana lape
control
□ □03-
■UUUA
3-A
Float-fixed vector
□ □□5-
■□□□b
5-fc
Fixed-float vector
□ □□7
7
Search character
□ □□fi
fl
Scan-quotes flag
□□□q
q
TAB column save
□□□a
!□
□ = LOaD, 1 = VERIFY
□ □□B
11
Input buffer pointer/number of
subscripts
□□□c
IE
Default DIM flag
□ □□D
13
Type: $ FF= string;
□ □= numeric
□ ODE
lA
Type: $ fi □ = integer;
□ □ = floating point
□ □□F
15
DaTa scan/LIST quote/memory
flag
□ QIQ
It
Subscript/FNx flag
□ □11
17
□ = INPUT;$4D = GET;
$Hfi=REaD
DUIE
Ifi
aTN sign/Comparison
evaluation flag
□ □13
IR
Current I/O prompt flag
-□□15
E^-El
Integer value
192
MACHINE LANGUAGE FOR COMMODORE MACHINES
Hex
Decimal
Description
U LJ ^ □
c c
nuiMici. 1 ifjui di y oiling oiciui\
nni.7 -
n m, A
U U Ji u
udoi iC/i 1 ipui di y oiling vouiui
LJ LJ JJ 1
0051
LJ LJ ^ JJ
E5-
Stank for tpmnorarv Qtrinn^
WiClwiX \\J\ Iwl 1 lli^wl Cll y oil II lUw
OOEE-
□ □E5
—J ^
37
Utilitv Dointer area
□ □Et-
□ 02ft
^ A-
Z P
Product area for multiolioation
U U u XJ
nnpr
U U Q
Z 1-
Pnintpr" Qtart-nf-RA^IH
n n PD-
U U C JJ
n n pp
U U C ij
Z c:_
*i J —
Z L
M b
Pnintpr" Qtart-nf-wsiriahlpc
1 \J\ \ 1 ICI . OlCll I \j\ Vdl ldl.^lC70
U U C X
nrr^n
U U Jj u
Z7-
Z A
rUHiici. old! I wi di 1 dyo
U UJ JJ
U U J u
Z q_
c;n
1 uiMioi . c?MU ui diidyo
j jj
nUllllCl. oUltl^ OlUld^C ^IIIUVIIIU
U U -J ^
U U J o
QZ
1 Itilitx/ ctrinn nriintor
^jiiiiiy oiiiiiy puiiiici
u u J r
nn^ft
U LU Ll
3 b
Pnintpr' linriit-nf-iripmnrw
1 wiiiid* iiiiiii \j\ iiidiiwiy
U U J n
LlLl 3 n
D f —
.c; A
f^iirrpnt RAQIf^ linp niiinKpr
wUIICiil D/AOIW IIIIC IIUIIIUCI
U U □ D
U U J
b U
Prp\/ini iQ PA^ir^ linp niimKor
riCVIUUo DMO 1 V»/ llllo IIUIIIUCI
\J \J D U
Liu 3 Lt
b Jj —
r p
'be
Pnintpr* RA^IH Qtatpmpnt fnr
u u J r
nnz; n
U U H U
b J —
LZ
•b^
f^iirrpnt FlflTB lino niimKpr
nnz:i.-
U U H Jj
nnz P
U U H C
b b-
r r
-b b
Oi irrpnt "R H T B sHHrocc
OUiicill 1/nJ.n dUUlcoa
n nz z
U U M 'I
b r —
L A
- b u
inpul VcUlUI
nnz c;
n nz L
b n
.7 n
ourreru Vdriauic ridrnc
n nz fl
u u s u
I Jj —
7 p
r^i irrpnt \/9ri£iHlp sHHrpcc
wUiiciii vdiiduic? duuicoo
n nz Q
nnz n
u U ^ n
7
r J
.7 Z
V/ariohIa nr\intar fnr TrnP/MPYT*
variauic; puiniei lor run/nriAX
LJ LJ ^ U
LJ LJ " \^
7 c;.
-7 L
lb
Y-^avp* OD-Qavp' BASIH
nnintpr q£i\/p
LJ LJ " J-'
77
r r
nomnari^on wmhni
1 i|jcii loii^i 1 wy 1 1 iii^ui
flnr^i imi ilfitnr
dwuui 1 luidiui
DDAE-
-□□53
7 A-
1 LJ
-Al
LJ -J
Mi^npllanpniJ^ work arpa
IVIIOV/wllCtI IwwUw Wwl i\ Cll wOj
nnintprQ nnH Qn nn
I^Vi/lllldO) dl ILI wl 1
DDSA-
-□□5b
LJ
LJ D
Jumn vector for functions
WUI 1 lli^ V wwiVI Iwl lUllwllVI lO
□ □57-
-□□b^
A7-
LJ f
n □
Mi^ppllanpoiiQ niimprip work
IVIIO^^IICII twwUO 1 lUI 1 Id Iw VVUI l\
Cll wCl
□ □tl
~ f
Acrijm#1" pynnnpnt
nnp,?-
U LJ O l_
LJ LJ O — J
-101
Anpiimafiti* nriAnticQS)
l^E
Accum#1 : sign
□ □b?
Series evaluation constant
pointer
□ □tfi
1^4
Accum#1 lii-order (overflow)
□ □tR-
-□□bE
1^5-
-IID
Accum#2: exponent, and so on
□ □bF
111
Sign comparison, Acc#1 versus
#2
□ □?□
HE
Accum#1 lo-order (rounding)
APPENDIX C — COMMODORE 64
793
Hex
Decimal
Description
□ □71-
•□□7E
113-
•114
Cassette buffer length/series
pointer
□ □73-
'□□fia
115-
13fl
CHRGET subroutine; get
BASIC character
□□7a-
■□□7B
lEE-
•1E3
BASIC pointer (within
subroutine)
□ □flB-
•□□flF
13q-
IA3
END seed value
Status word ST
□□qi
IAS
Keyswitch PI a: STOP and
RVS flags
□□qe
lAh
Timing constant for tape
□□q3
1A7
Load = ^; verify = l
Serial output: deferred character
flag
□ □qs
i<q
Serial deferred character
□□qt
15^
Tape EOT received
□□q7
151
Register save
□□qfl
15E
How many open files
□□qq
153
Input device, normally □
□□qft
15^^
Output CMD device, normally 3
□□qB
155
Tape character parity
□□qc
15t
Byte-received flag
□ □qD
157
Direct = $ fi □/R U N = □ output
control
□□qE
15fl
Tape pass 1 error log/character
buffer
□□qp
15q
Tape pass E error log corrected
□□&□-
■□□aE
It^-
■IbE
Jiffy Clock HML
□ □A3
lt.3
Serial bit count/EOI flag
It^
Cycle count
□□as
lt>5
Countdown, tape write/bit count
□□at
Itt
Tape buffer pointer
□□a?
lt7
Tape write leader count/read
pass/inbit
□□aa
Itfi
Tape write new byte/read
error/inbit count
□□aq
itq
Write start bit/read bit error/stbit
□□aa
17^
Tape Scan ;Cnt; Load;
End/byte assembly
□□as
171
Write lead length/read
checksum/parity
□ □ac-
-□□aD
17E-
-173
Pointer: tape buffer, scrolling
794 MACHINE LANGUAGE FOR COMMODORE MACHINES
Hex
Decimal
Description
□ □AE-
□ □AF
17<-
175
Tape end address/end of
program
□ □BD-
□ □31
17t-
177
Tape tinning constants
00B2-
□ □33
17 fl-
17H
Pointer: start of tape buffer
QUBA
Ifi^
1 = tape timer enabled; bit
count
□ □35
Ifil
Tape E0T/RSE3E next bit to
send
□ □Bt
IflE
Read character error/outbyte
buffer
□ □37
ia3
Number of characters in file
name
□ □Bfl
Ifl^
Current logical file
□ □Bq
IflS
Current secondary address
□ □BA
lat
Current device
□ □33-
-□□BC
lfl7-
-Ififi
Pointer to file name
□ □BD
laq
Write shift word/read input char
□ □BE
mD
Number of blocks remaining to
write/read
□ DBF
iRi
Serial word buffer
□ □€□
l'=IE
Tape motor interlock
□ OCl-
-□□CE
1R3-
-1R4
I/O start address
□ □C3-
■OQCA
1R5-
-lit
Kernel setup pointer
□ □C5
l'=17
Last key pressed
□ □Ct
IRfl
Number of characters in
keyboard buffer
□ □C7
iqq
Screen reverse flag
□ □Cfl
EDO
End-of-line for input pointer
□ □C^l-
-□□CA
E^l-
-E^E
Input cursor log (row, column)
□ □CB
£□3
Which key: if no key
□ □CC
En<
□ =flash cursor
□ □CD
—11—11—
£□5
Cursor timing countdown
□ □CE
3 n r
Character under cursor
n n o*p
E^7
Cursor in blink phase
□ □D^
EDfl
Input from screen/from
keyboard
□ □Dl-
-□□Da
E^R-
-El^
Pointer to screen line
□ □D3
Ell
Position of cursor on above line
QUDA
ElE
□ = direct cursor; else
programmed
□ □D5
E13
Current screen line length
APPENDIX C — COMMODORE 64
795
Hay
Decimal
L/croOr IfJUUi 1
DDDh
El/?
Row where cursor lives
□ 0D7
E15
Last inkey/checksum/buffer
□ □Dfl
Elfc
Number of INSERTS
outstanding
□ DDR-
□ 0F5
E17-
BAE
Screen line link table
□ □F3-
□ OF^
EAA
Screen color pointer
□ □F5-
□ DFt
EAS-
Keyboard pointer
□ □F7-
□ □Ffl
2A7-
E^6
RS-232 Rev pntr
OQFq-
DDFfi
E^R-
E5^
RS-232 Tx pntr
□ □FF-
DIOA
E5b-
Ebt
Floating to ASCII work area
□ IDO-
103E
E5fc-
31fl
Tape error log
□ IDD-
□ IFF
ESfc-
511
Processor stack area
□ 500-
OEsa
51E-
tDD
BASIC input buffer
□ E5S-
□ EtE
yoi-
bl^
Logical file table
0Et3-
□ Etc
bll-
tE^
Device number table
OEfcD-
□ E7t
tEl-
t3^
Secondary address table
□ 277-
□ EfiD
b31-
t<Q
Keyboard buffer
□ Efil-
□ EfiE
■b<E
Start of BASIC memory
Q2&3-
□ Efl^
t43-
Top of BASIC memory
□ Efl5
Serial bus timeout flag
OEflt
yAh
Current color code
□ Efl7
yA7
Color under cursor
□ Eflfl
l,A&
Screen memory page
□ Eflq
hA^
Maximum size of keyboard
buffer
□ EflA
t50
Repeat all keys
□ EfiB
t51
Repeat speed counter
□ EflC
b5E
Repeat delay counter
□ EflD
hS3
Keyboard Shift/Control flag
□ EflE
hSA
Last sliift pattern
□ EflF-
-□ERD
t55-
-t5t
Keyboard table setup pointer
□ Eqi
t57
Keyboard shift mode
□ E^E
t5Q
□ = scroll enable
□ ER3
fcSR
RS-232 control reg
DER^
tbO
RS-232 command reg
DEq5-
■□ERt
bbl-
-btE
Bit timing
□ Eq7
bb3
RS-232 status
□ ERA
tt<
Number of bits to send
□ ERR-
-□ERA
tt5
RS-232 speed/code
□ ERB
tfc7
RS232 receive pointer
OERC
RS232 input pointer
796 MACHINE LANGUAGE FOR COMMODORE MACHINES
Hex
Decimal
Description
□ ERD
yy^
RS232 transmit pointer
05RE
t70
RS232 output pointer
-OEftD
t.71-
-t7E
IRQ save during tape I/O
□ ERl
fc73
CI ft E (NMI) interrupt control
OEfiE
h7A
CIA 1 timer A control log
t75
CIA 1 interrupt Log
□ EA^
b7t
CIA 1 timer A enabled flag
□ EA5
tj77
Screen row marker
02C0-
-□EFE
7DA-
-7tb
(Sprite 7)
□ 300-
-0301
7bfl-
-7tjR
Error message link
□ 3DE-
-0303
770-
-771
dAoIO warm start link
Q3UA-
-D305
77E-
-773
Crunch BASIC tokens link
□ 3Dfc-
-0307
17 A-
-775
Print tokens link
□ 3Dfl-
-030'^
77b-
-777
Start new BASlo code link
03DA-
-D30B
77fl-
-77'=l
Get arithmetic element link
□ 3DC
730
SYS A-reg save
□ 3DD
7fll
SYS X-reg save
03DE
7flE
SYS Y-reg save
□ 30F
7a3
SYS status reg save
□ 31D-
-031E
7&A-
-7fl5
OSR function jump (Dtr^iO)
0314-
-0315
7flfl-
-7fl'=l
IRQ vector (EA31)
□ 31t-
-0317
7R0-
-7R1
Break interrupt vector (FEfcb)
□ 31fl-
-031R
7SE-
-7m
NMI interrupt vector (FE^7)
03ia-
-031B
7R4-
-7R5
OPEN vector (F3'iA)
031C-
-031D
7Rt-
-7R7
CLOSE vector (rcHl)
□ 31E-
-031F
7Rfl-
-7RR
Set-input vector (FEOE)
□ 3ED-
-03E1
fiOO-
-flOl
Set-output vector (FS5G)
032E-
-03E3
flOE-
-fl03
Restore I/O vector (F3 3d)
Q3EA-
-03E5
&UA-
-flD5
l__..X ..A aX A / TTI "1 ^ T \
Input vector (F157)
□ 3Et-
-03E7
fiOb-
-fl07
Output vector (F 1 C A)
□ 3Efl-
-032"^
flOfl-
-flOi^l
Test-STOP vector (FbED)
□ 3Ea-
-D3EB
fllO-
-All
GET vector (Fidt)
□ 3EC-
-03ED
fllE-
-□13
Abort I/O vector (r d dr )
□ 3EE-
-03EF
HI/"
-O 1 b
U o K vector (r b b b)
n ~i T n
-□331
filb-
-fll7
LUAi) linK (rHiib;
□ 33E-
-0333
fllfi-
-fliq
SAVE link {F5ED)
□ 33C-
-D3FB
fiEfi
-IDiq
Cassette buffer
03-^0-
-D37E
a3s
(Sprite 13)
□ 3aD-
-03BE
-q5a
(Sprite \A)
□3cn-
-D3FE
SfcO
-lOEE
(Sprite 15)
QADQ
-07FF
10E4
-E047
Screen memory
n&DQ
-RFFF
EO^fl
-4oq5R
BASIC RAM memory
APPENDIX C — COMMODORE 64
797
Hex
Decimal
Description
o n n n
n ti TP TP
3E7tfl-
Alternative: RON plug-in area
T\ n n n
-BFFF
BON: BASIC
n n n n
-BFFF
-5R151
Alternate: RAN
/-t n n n
-CFFF
-53E<7
RAN memory, including
alternative
T% n H r1
-DDdE
^ T T X n
-53dH4
Video chip (bSbb)
U U-
-5<3DD
bound cnip (bbol SID)
DADO
-DBFF
-5t3iq
Color nybble memory
DCDD-
-DCDF
-5t335
Interface chip 1, IRQ ( bSEt
CIR)
DDDD
-DDDF
-5b5Rl
Interface Chip E, NNI (tEEb
CIA)
DDDD-
-DFFF
-535q4
Alternative: character set
-FFFF
-b5535
RON: operating system
-FFFF
S73AA-
-t5535
Alternative: RAN
798 MACHINE LANGUAGE FOR COMMODORE MACHINES
CIA 1 (IRQ) (6526) Commodore 64
Paddle SEL
Joystick
$DCOO
A . B
R
. L , D . U
PRA
56320
Keyboard Row Select (inverted)
$DC01
Joystick 1
PRB
56321
Keyboard Column Read
$DC02
$FF —
All Output
UUHA
$DC03
$00 —
All Input
DDRB
56323
$DC04
$DC05
Timer A
TAL
TAH
56324
56325
$DC06
$DC07
Timer B
TBL
TBH
56326
56327
$DCOD
Tape
Input
Timer Interr.
B , A
lER
56333
Time Timer
$DCOE
One Out
shot pode
PDL A
out 1 start
CRA
56334
Time Timer
$DCOF
One Out
shot fnode
PBC B
out , start
CRB
56335
Figure C.8
APPENDIX C — COMMODORE 64
799
CIA 2 (NMI)
(6526)
Commodore 64
Serial
In
Clock
In
Serial
Out
1 1
Clock
Out
1 1
ATN
Out
1 — : 1
RS-232
Out
1 1
Video
Block
DSR
In
CTS
In
F
DCD*
In
>arallel I
Rl*
In
Jser Po
DTR
Out
rt
RTS
Out
RS-232
In
In
In
Out
Out Out
$3F
Out
Out
Out
$06 For RS-232
Timer A
Timer B
RS-232
In
Timer
B
Timer
A
Timer
A Start
Timer
B Start
PRA
PRB
DDRA
DDRB
TAL
TAH
TBL
TBH
ICR
CRA
CRB
Figure C.9
200 MACHINE LANGUAGE FOR COMMODORE MACHINES
C64 Memory Map
6566 Video — Sprite Registers
Sprite Sprite
7
DOOO
DOOE
D001
DOOF
□027
D02E
Position
Color
D011
D012
D013
D014
D016
Sprite Bit Positions
5 4 3 2
D010
D015
D017
D01B
D01C
D01D
D01E
D01F
X-position high
Sprite Enable
Y-expand
Background Priority
Multicolor
X-expand
Interrupt: Sprite collisn
Interrupt: Sprite/Backgrd coll
Sprite
Sprite
7
53248
53262
53249
53263
53287
53294
53264
53269
53271
53275
53276
53277
53278
53279
C64 Memory Map
6566 Video -
Control and Misc. Registers
Extnd Color
Bit Map
Dsply EnabI
Row Selct .
Y-Soroll
Raster Register
Light Pen Input
X
Y
S326S
53266
53267
53268
X
Reset
Multl Color
Colm Sel .
X-Scroll
A
D018
vm13
Screen (Video Matrix)
vm12 vmll
vmlO
Character Base
cb13 cb12 cb11
X
53272
D019
IRQ
IRQ sence
1 1
SSC , SBC
RST
53273
D01A
IRQ Enable
Light
Pen ,
Collision
Spit Back
Rastr
53274
COLOUR REGISTERS
D020
Exterior
53280
D021
Background #0
53281
0022
Background #1
53282
D023
Background #2
53283
D024
Background #3
53284
D025
Sprite Multlcotor #0
53285
D026
Sprite Multicolor #1
53286
Figure CIO
APPENDIX C — COMMODORE PLUS/4 201
SID (6581) Commodore 64
V1
D400
D401
V2
D407
D408
V3
V1 V2 V3
D40E
D40F
— Frequency
L
H
54272 54279 54286
54273 54280 54287
D402
D409
D410
Pulse Width
L
CAn^A CAf^OH CilOOO
54274 54281 54288
D403
D40A
D411
H
54275 54282 54289
D404
D40B
D412
Voice Type
NSE 1 PUL 1 SAW 1 TRI
KEY
1 1 1
54276 54283 54290
D405
D40C
D413
Attacl<
Time
2ms-8sec
1 1 1
Decay
Time
6ms-24sec
1 1 1
54277 54284 54291
D406
D40D
D414
Sustain
level
1 1 1
Release time
6ms-24sec
1 1 1
54278 54285 54292
Voices
(write only)
D415
L
54293
D416
Filter Frequency
H
54294
D417
Resonance
1 1 1
Filter voices
|eXT| V3 I V2 I VI
54295
D418
Passband
V3
OFF 1 HI 1 BD 1 LO
1
Master
Volume
1 1 1
54296
Filter & Volume
(write only)
Paddle X 54297
Paddle Y 54298
Noise 3 (random) 54299
Envelope 3 54300
Sense
(read only)
Special voice features (TEST, RING MOD, SYNC) are
omitted from the above diagram.
Figure C.11
D419
D41A
D41B
D41C
202 MACHINE LANGUAGE FOR COMMODORE MACHINES
Commodore PLUS/4 "TED" Chip-
Preliminary
At time of publication the Commodore 264 (alternatively called Plus/4) and
a related machine, the Commodore 16, are not commercially available.
Design details could change before commercial release.
On the prototype units, much of zero-page is the same as for VIC and
Commodore 64; in particular, the Basic pointers (SOB, SOV, etc.) are the
same.
Memory Map, Preliminary
Much of zero-page is the same as for the Commodore 64. Some differ-
ences, and other information:
Hex
Decimal
Description
□ □73-
□□aa
115-13a
(CHaRGET not present)
□□q?
151
How many open files
□□qa
152
Input device, normally □
□ □RR
153
Output CMD device, normally 3
□□ac
17S
Current logical file
□ □fiD
173
Current secondary address
□ QAE
17^
Current device
□□aF-
□ □BD
175-17fc
Pointer to file name
□□ca-
□□cq
EDO-B^l
Pointer to screen line
□□ca
EUE
Position of cursor on above line
□ □CD
RUS
Row where cursor lives
□ □EF
23q
Number of characters in
keyboard buffer
□ 3K-
-□315
7aa-7aq
IRQ vector (CE^E)
•□317
7q^-7qi
Break interrupt vector (?AAB)
□3ia-
■□3iq
7qE-7q3
OPEN vector (EF53)
(Most other vectors are similar to the C64, but are two locations lower)
□ 5^^-^5DE lea^-lEaE USR program jump
D5nq-D51E lEaq-lEqa Logical file table
□ 513-0510 lEqq-130a Device number table
□ 51D-^5Efc 13^q-13ia Secondary address table
□ 5E7-^53^ 13iq-13Ea Keyboard buffer
□ a^^-DBE7 2DAei-3DA7 Color memory
□ CDD-DFE7 3^7E-4^71 Screen memory
APPENDIX C — B SERIES
203
IN:
IN: IN: IN:
OUT:
OUT:
OUT;
OUT:
SERIAL CLOCK ^ ^ TAPE
TAPE
, MOTOR
ATN
SERIAL
TAPE
CLOCK
FFOO
FFOl
T1
L _
H "
FF02
FF03
rrut
FF05
TIMERS
T2
T3
1 1
FF06
TEST
ECM , BMM , BLANK
ROWS .
Y-ADJUST
FF07
RVS OFF ,
PAL , FREEZE , MCM
COLUMNS
X-ADJUST
FF08
KEYBOARD LATCH
FF09
IRQ FLAG
1 i
LP
PAST
rrUA
lER
T3 . V -v 'l^ft T2 ,
T1
LP
RAST
FF08
RASTER CONTROL
FFOC
FFOD
CURSOR CONTROL
FFOE
FFOF
SOUND:
VOICE 1
VOICE 2
FF10
VOICE
2 HI
rr 1 1
SOUND SELECT
VOLUME
CC 1 o
rr 1 z
1 BIT MAP BASE
R BANK
VOICE
1 HI
PP 1 "5
pp 1 J
CHARACTER BASE
SCLOCK
STATUS
FF14
VIDEO MATRIX
FF15
FF16
LUMINANCE
COLOR
1
FF17
2
FF18
1
ACKGROUND COLORS
3
FF19
■ . •'
4
FF1A
- '
FF1B
CHARACTER POSITION RELOAD
FF1C
1
FF10
VERTICAL LINE REGISTER
FFIE
HORIZONTAL POSITION REGISTER
FF1F
BUNK COUNT
V SUBADDRESS
65280
65281
65282
65283
65284
65285
65286
65287
65288
65289
65290
65291
65292
65293
65294
65295
65296
65297
65298
65299
65300
65301
65302
65303
65304
65305
65306
65307
65308
65309
65310
65311
FF3E
ROM SELECT
65342
WRITE ONLY:
FF3F
RAM SELECT
65343
Figure C.12
204 MACHINE LANGUAGE FOR COMMODORE MACHINES
IDDD-FFFF 4QRt-t5535 BASIC RAM memory
flDOD-FFFF 3E7ta-t5535 ROM: BASIC
FF00-FF3F t5EflD-t5343 TED I/O control chip
B Series (B-128, CBM-256, etc.)
The Great Zero-Page Hunt
Zero page has a different meaning on the B series. There are several
zero pages. Usually, you'll want to use values from bank 15 (the ROM
bank, where system variables are kept); but if you are writing programs
that will reside in a different bank, you'll have all of zero page (except
locations □ and 1) completely at your disposal.
If you need space in bank 15 zero page, you'll need to do some looking
around. Addresses $Et to $FF are not used by the system. Locations
$ED to $EB and to $fcE are work areas available for temporary
use.
Most zero-page locations may be copied to another part of memory so
that their original contents can be restored after use. The programmer
should take great care, however, in modifying the following locations, which
are critical within the operating system or BASIC: $1A, $1D to $51,
$5D to $A1, $A3, $5B, $7fl, SflS-fl?, $RE to SAB, $C0 to $E5.
Memory Map
The following information applies to B systems released after April 1983,
which contain a revised machine language monitor. (If POKE b , □ : SYS
t doesn't bring in a monitor display complete with a "period" prompt, you
have an incompatible version.)
Notable features as compared to previous Commodore products include:
— CHRGOT is no longer in RAM. Wedge-type coding must be inserted at links
$DE'^Eand$QEao, which Is likely to make the job easier.
—BASIC vectors have "spill." Now, for example, there are discrete "start of
variables" and "end of variables," distinct from end-of-BASIC and start-of-
arrays. Three-byte vectors (including bank number) are not uncommon.
—The "jump table" at top of memory is still accessible and reasonably consistent
with previous Commodore products.
—Simple machine language programs will fit Into the spare 1 K of RAM at
$04D0to$D7FF without trouble. Large programs must be Implemented
APPENDIX C — B SERIES 205
either by plug-in memory (RAM or ROM) in bank 15 or by being placed into
another bank (preferably bank 3). Supplementary code will be needed to
make all the coding components fit.
The following map contains BASIC addresses specific to the B256/80;
references to banks OXo A are also specific to that machine. Most of the
map is of general usage, however.
ALL BANKS:
□ □□□ □
□ □□1 1
BANK 0: Unused.
BANK 1:
□□□5-FDDD
FABE-FBOQ
BANK 2:
B256:
□DOE-FFFF
B1E&:
□005-FFFF
tSD"^ execution register
bBDR indirection register
BASIC program (text) RAM
Input buffer area
E-fc5535 BASIC arrays in RAM
E-fc5535
BANK 3: (B256 only)
□□□E-7FFF a-357fc7
flDDO-FFFF 3E7tfl-t5535
BANK A : (BESt only)
□□□E-FBFF E-t4511
FCDD-FCFF t451E-t47t7
FDOD-FFFF t47tfl-b5535
BANKS 5 to 14: Unused.
BANK 15:
BASIC variables, arrays and
strings
Key definitions
Unused RAM.
BASIC variables in RAM
BASIC strings (top down) in
RAM
Unused RAM (descriptors?)
Current KEY defiriitions
□ □□E-
■QQUA
E-
■A
USR jump
□ □□5-
'□□□a
5-
■fl
TI$ output elements:
H,M,S,T
□ □DR-
■□□□B
-11
Print Using format pointer
□ □□C
lE
Search character
□ □□D
13
Scan-between-quotes Flag
□ □□E
lA
Input point; number of
subscripts
□ □□F
15
Catalog line counter
□ QID
It
Default DIM flag
□ □11
17
Type: E55= string, □ = integer
206
MACHINE LANGUAGE FOR COMMODORE MACHINES
n n 1 3
UU Jl c
1, ft
JJ U
Type: 1 E fl = integer,
= floatina DOint
n n 1
Crunch flaa
nm z
UU Ji'i
\Z LI
Subscript index
UU Jl 3
1 JJ
lnput= 0; get= t4; reacl = 15S.
n n 1. c
U U Jj b —
U U JJ n
Disl< status worl< values
n n 1 n
U U Ji n
L- □
Current I/O device for prompt
suppress
nm.R—
U U ii D —
U Ll Jl
E7-
•Sfl
Integer value
nni.n_
U U JJ 1/
LI U JJ J.
gq-
■31
Descriptor stacl< pointers
nnpri—
u u c u~
U U C Jl
32-
33
Vector to string descriptors
U U C C"~
nnpR
UUCD
43
Miscellaneous work pointers
u u cu-
M —1
■Ah
Start-of-BASIC pointer
rl n 31?
UUcf -
n n ^3 n
u U J u
Z 7-
End-of-BASIC Dointer
n n 1
UUdl-
-U U J c
D U
Rtart-nf-Varlables Dointer
UUdd-
■ U U J H
End-of-Variables Dointer
U U J 3-
-U U J D
-q4
Start-of-Arravs Dointer
U U J r -
'U U J □
^ -J
End-of-Arrays pointer
nmQ-
U U J n
U U 3 £1
-J 1
-Sfl
Variable work pointer
-nmr
U U ^
-tiQ
Bottom-of-Strings pointer
n m
uUdU-
- U U J £i
LL-
CS jj
DC
IJtilitv strina oointer
u u J r -
- U U H Jl
D J
Top of string memory pointer
nnziP-
U U H C
U U H J
-ti7
Current BASIC line number
n nz z _
U U M H "
f. A-
O 1
Old BASIC line number
-0047
70-
-71
Old BASIC text pointer
n nz Q
U Um n -
n n z n
-1 c
1 M
Data line number
nnzR
u u ^ D-
n nz r
r zi
-7
Data text oointer
nnzn.
-finz'P
U LJ H Ij
77-
-7fl
inout oointer
u u ^ r -
U U D U
7q-
-AG
LJ LJ
Variable name
U U 13 JJ
U U P J
LJ M
-83
Variable address
U U _J *-1
LJ l_l ^ u
&A-
-flb
For-loop pointer
U U 3 1
LJ Ul ^ LJ
&1-
-flfl
Text pointer save
nrma
U U 3 n
Comparison symbol
accumulator
□ □5B-
-DD5D
qi-
-qe
Function location
□ □5E-
-DDtO
Working string vector
□ □tl-
-□□t3
R7-
-qq
Function jump code
□ □t4-
-OOtE
100
-110
Work pointers, values
□ OfcF
111
Exponent sign
QD70
112
Acum string prefix
D071
113
Acum#1 : exponent
□ □7E
-□075
114
-117
Accum#1: mantissa
APPENDIX C — B SERIES
207
□ □7t
iia
□ □77
iiq
□ Q7a
l^Q
□ □7R-
□ □7E
lEl-
•lEti
□ □7F
127
□ □&□
lEa
□ Dfll-
UQ&A
lEq-
■135
□ OfiB-
□ □67
133-
-135
DDflfl-
□□aq
13ti-
■137
□ □flB-
□□aE
i3q-
■14E
□ □SF
1^3
□□qo-
□□q2
-14 1
□□q3-
□□qs
147-
-14H
□ □Rfc-
15D-
-155
□□qaa
□oqq-
□□qs
153-
1 f— r—
-155
DORC
15t
□ □RD
157
□ □RE
15a
□ □^F
i5q
□ □AO
ODRl
iti
ltd
□ □Afc-
■□□Aa
Ifctj-
-ita
□ OftR
ifcq
□ □AA
17 □
□ □ftB
171
□ □AC-
-□□AD
175-
-17 3
□ □AE-
-□□B3
174-
-i7q
□ □B^
lao
□ □B5
lai
onB7-
-□□Ba
ia3-
-ia4
DDBR-
-□□BA
las-
-lafc
□ □BB-
-□□BC
ia7-
-laa
□ □BD
laq
ODBE
iqa
□ DBF
iqi
□ □CD-
-□□CI
iqa-
-iq3
□ □C5-
-□□C3
iq^-
-iq5
Accum#1 : sign
Series evaluation constant
pointer
Acum#1 hi order (overflow)
Accum#2
Sign comparison, Acc#1 versus
#2
Acc#1 low-order (rounding)
Series, work pointers
BASIC text pointer
Input pointer
DOS parser work values
Error type number
Pointer to file name
Pointer: tape buffer, scrolling
Load end address/end of
program
I/O start address
Status word ST
File name length
Current logical file
Current device
Current secondary address
Input device, normally
Output CMD device, normally 3
INBUF
Keyswitch PI A: stop key, etc.
IEEE deferred flag
IEEE deferred character
Segment transfer routine vector
Monitor register save
Monitor stack pointer save
Monitor bank number save
Monitor IRQ save/pointer
Monitor memory pointer
Monitor secondary pointer
Monitor counter
Monitor miscellaneous byte
Monitor device number
Programmable key table
address
Programmable key address
208 MACHINE LANGUAGE FOR COMMODORE MACHINES
-UUL r
1 Q t_
1 Q Q
Ji n T
Drtintarc tn ohsinnp
roinieib lu i/iiaiiyts
prOyrammaDie Key lauic
n n o n
n n o n
-□□CH
!!] n n
3 n 1
dUl
rOinxer lo screen iirie
OOCft
EOE
Screen line number
□ OCB
dud
rosition OT cursor on line
□ □CC
3 n /■
u — lexi moue, eise grapriics
mode
□ UCD
D n c
iveypress variauie
□ OCE
n r
cUh
uiQ cursor coiumn
n n TTi
□ UCF
^ n "5
d U r
UIQ cursor row
□ UDU
D n A
c U □
iNew cnaraCicr iiay
n n "n 1
D n a
c U n
iNumuor uT K6yo in Kcyuuciru
buffor
PI n "pv "n
3 1 n
d Jj U
uuoies Tiag
n n
d Jj Jj
men Key counier
did
Cursor type flag
n n T-\ i—
did
ocreen line lengin
n n r\ r
□ UDb
iNUmuer ot Keys in Key uuner
□ □D7
E15
Key repeat delay
n n T\ n
□ □Do
dlb
Key repeat speed
n rrn Q
n rrn 7\
-UUUii
dli r-
31 A
-C Jl u
1 emporary vanauics
3 1 Q
c Jj n
/^i iri*Ant Ai itm it Ahoro/^tAr
uurrsni ouipui cnaracicr
P 3 n
ecu
Trtr* lino of /^i irront c/^roon
■ up lliio Ul OUIlclll ouiccll
n rTnr\
3 P 1
CC ii
Douum line OT sortjcn
P 3 3
CCd
1 Aft A^AA At AI lt*l*Ant OAI*AAn
Len OT C/Urrcni screen
n nnp
CC3
rviyni euyc ui boreeii
n m? n
U U£i U
t^A\/0 ' ^ CI C — MArtA" 1.3 7 — I^Al/
rseys. c ZD □ — none, jj c r — Key,
111 — chift
jj ij ij — snin
DDEl
EES
Key pressed: 255 = no key
-U Uri3
3 3 C_
d d b-
3 3a
-c c n
Line wrap tsiis
d5b
Hex to Dinary siaging area
n 1 n n
n 1 n 7\
-U JjUA
3 C L
dbb-
3 L L
-ebb
Nil im APIA tA AC^II lAfArl^ Of* AO
iNunienc 10 mol/Ii won\ area
n 1 n n
U Jj u u-
n 1 W
3 C L.
cab-
- 3 Jj U
OlauiN dlect
OlFF
511
Stack pointer save location
DEOO-
-OEDF
51E-
-5E7
File name area
OEIO-
-DEEb
5Ea-
-55D
Disk command work area
□ 555-
-□S5b
5R7
Miscellaneous work values for
WRIT, etc
0E57
5qq
"Bank" value
Output logical file (CMD)
□Esq
bDl
Sign of TAN
APPENDIX C — B SERIES
209
-0E5D
bOE-
-^□5
Pickup subroutine;
miscellaneous work values
□asE-
-0E7b
^□b-
-1.3U
PRINT USING working
variables
□ EflD-
-DEfll
-hAl
Error routine link [6555]
□ EflE-
-□Sfl3
fc-^E-
-t^3
Warm start link [flSCD]
□ Efl^-
-□EflS
-hAS
Crunch token link [flflCE]
□ Efit-
-DEfi?
-hA7
List link [aqp^]
□aaa-
-OEflR
hA&-
Command dispatch link [fl754]
□ EflR-
-□EflB
hSQ-
-t51
Token evaluate link [qtBl]
□ EflC-
-□EflD
fc5E-
-t53
Expression eval link [q5C4]
□ EflE-
-□EflF
-b55
CHRGOT link [BaEC]
□ ERD-
-OEHl
-fc57
CHRGET vector [Ba3E]
□ ERE-
-□Eq3
b5fl-
-bsq
Float-fixed vector [BaiE]
DER4-
-0ER5
tbD-
-ttl
Fixed-Float vector [qD3q]
DEqt-
-□ER7
ttE-
-tb3
Error trap vector
□ ERfl-
-□Eqq
-bb5
Error line number
□E^a-
-□ERB
bbb-
-bb7
Error exit pointer
□ ERC
Stack pointer save
OERD-
-□ERF
-t71
Temporary TRaP, DISPOSE
bytes
OEAD-
-□EAB
t7E-
-t77
Temporary INSTR$ bytes
□ Eftt-
-□EA?
fc7fl-
-t7q
Bank offset
□ 300-
-□3D1
7fcfl-
-7fcq
IRQ vector [FBEq]
□ 30E-
-□3^3
77^-
-771
BRK vector [EEEl]
-□3^5
77E-
-773
NMI vector [FCaa]
□ 3Db-
-□3D7
77^-
-775
OPEN vector [FbBF]
□ 3Dfl-
-□3^n
77t-
-777
CLOSE vector [F5ED]
□ 30a-
-□3^B
77fl-
-77q
Connect-input vector [F5^q]
□ 3DC-
-□3DD
7fl^-
-7fll
Connect-output vector [F5a3]
□ 3DE-
-□3DF
7flE-
-733
Restore default I/O vector
[Fbat]
□ 31D-
-□311
l&A-
-7fl5
Input vector [F^qC]
□ 31E.
-□313
7fib.
-757
Output vector [F4EE]
U31A-
-□315
7flfi
-7flq
Stop key test vector [FqfcB]
□ 31b
-□317
7q^
-7qi
GET vector [FA3B]
□ 31fl
-□3iq
7qE
-7q3
Abort all files vector [Ft7F]
031R
-0316
7q4
-7q5
Load vector [F7<t]
□ 31C
-□31D
?qb
-7q7
Save vector [Ffl^C]
□ 31E
-□31F
7qfl
-7qq
Monitor command vector
[EE77]
210 MACHINE LANGUAGE FOR COMMODORE MACHINES
□3ED-03E1 flQO-flQl
□354-D3E5 flO<-flD5
□ 3Et-
■□3E7
•a^7
□ 3Ea-
■□3ER
ana-
•a^q
□3aa-
■□3EB
ai^-
ail
□ 3EC-
-□3ED
aiE-
•ai3
□ 3EE-
■□3EF
ai4-
•ai5
□ 33D-
-□331
aib-
•ai7
□ 33E-
•0333
aia-
•aiq
□ 334-
■□33D
aED-
•BEq
□ 33E-
■□347
a3^-
■a3q
03A&-
□ 351
a4^-
•a^q
□ 35E-
□ 354
a5^-
•a5E
□ 355-
■□357
a53-
•a55
□ 35fl-
■□35A
•flsa
□ 35B-
■□35D
asq-
ati
□ 35E
atE
□ 35F
ati3
□ 3t^
ab4
□ 3tl
ats
□ 3b3-
■□3tb
at7-
37^
□ 3bq
a73
□ 3tR-
□ 3fcB
a74-
fl75
□ 3bF-
□ 371
a7q-
aai
□ 375
aa5
□ 37t-
□ 377
aab-
aa7
□ 37A
aq^
□ 37B
aqi
□ 37C
aqE
□ 37D
aq3
□ 3fl^-
□ 3fiE
aqt-
aqa
□ 333-
□3qt.
aqq-
qia
Keyboard control vector [E^IF]
Print control vector [ED IF]
IEEE send LSa vector
[FE74]
IEEE send TSa vector
[FEaD]
IEEE receive byte vector
[F30R]
IEEE send character vector
[FEq7]
IEEE send untalk vector
[FEaB]
IEEE send unlisten vector
[FEaF]
IEEE send listen vector
[FE34]
IEEE send talk vector [FE3^]
File logical addresses table
File device table
File secondary address table
Bottom of system memory
Top of system memory
Bottom of user memory
Top of user memory
IEEE timeout; □ = enabled
O = load; IE a = verify
Number of open files
Message mode byte
Miscellaneous register save
bytes
Timer toggle
Cassette vector (dead end)
Relocation start address
Cassette motor flag (unused)
RS-232 control, command
RS-232 status
RS-232 handshake input
RS-232 input pointer
RS-232 arrival pointer
Top of memory pointer
Programmed key lengths
APPENDIX C — B SERIES
211
□ 3^7
RVS flag
Q3Rfl
RED
Current line number
□3qq
Temporary output character
save
03qft
Rsa
□ = normal, E 5 5 = auto insert
RS3
D = scrolling, 1 E fi = no scroll
□ 3'=IC
Miscellaneous work byte for
screen
□ 3^0
R55
Index to programmed key
□3qE
Scroll mode work flag
Q3qF
qa?
Bell mode flag
□ BAD
Indirect bank save
03A1-
-D3aft
RER-
-R3fl
Bit mapped tab stops
□ 3aB-
-U3BA
R3R-
-R^a
Keyboard input buffer
Q3B5-
-D3Bt
KR-
-R5D
Key word link [ERIB]
□ 3Ffl-
-D3FR
IDlt-
-1D17
Restart vector
□ 3Fa-
-D3FB
IDia-
-IDIR
Restart test mask
□ -^DD-
-D7FF
1D2<-
-ED47
Free RAM (reserved for DOS )
□
-DFFF
ED^fl-
-4DS5
Reserved for plug in RAM
-IFFF
^DRt-
-fliqi
Reserved for plug in DOS ROM
-7FFF
fllRE-
-E37ti7
Reserved for cartridges
&UDQ-
-BFFF
3E7tfl
BASIC ROM
CDDD-
-CFFF
4R15E
-53E47
Unused
DDDD
-D7CF
53E4fl
-55E47
Screen RAM
DflOD
-DflDl
55ERt
-55ER7
Video controller hSAS
DADO
-DAIC
SSflDfl
-SSABEd
Sound interface device tSfll
DBDD
-DBDF
-StD?^
Complex interface adaptor
bBEt
DCDD
-DCDF
5t.3ED
-5t335
Complex interface adaptor
t,5Et
DDDD
-DDD3
5t57t
-5t57q
Asynchronous communications
lA b551
DEDD
-DED7
5t.a3E
-5tfl3q
Tri Port Interface Adaptor
t5E5
DFDD
-DFD7
57Dflfl
-57Dq5
Tri Port Interface Adaptor
t5E5
EDDD
-FFFF
573^^
-t5535
Kernal ROM
The above table shows contents for the link and vector addresses at $0280
to $0295; these are taken from a recent B-128.
1
272
MACHINE LANGUAGE FOR COMMODORE MACHINES
6545 CRT Controller
D800
55296
D801
55297
Typical Value
(Decimal)
Horizontal Total
108 or 126 or 127
1
Horizontal Cliar Displayed
80
2
Horizontal Sync Position
83 or 98 or 96
3
y Sync Width ^
15 or 10
4
Vertical Total
25 or 31 or 38
5
Vert Total Adjust
3 or 6 or 1
6
Vertical Displayed
25
7
Vert Sync Position
25 or 28 or 30
8
Mode
9
Scan Lines
13 or 7
10
Cursor Start
96 (blink) or
or 6 (underline)
11
Cursor End
13 or 7
12
13
1^
— Display Address —
L
14
15
u
— Cursor Address —
L
Varies
Varies
16
17
1^
— Liglit Pen In
L
Most Registers are Write Only 14/15 are Read/Write
16/17 are Read Only
Registers 10, 14 and 15 change as the cursor moves
Figure C.13
APPENDIX C — COMMODORE 128
213
6525 Tri Port
DEOO
NRFD
NDAC
EOl
DAV
ATN
RFN
56832
DE01
Sense
Cassette
Motor
Out
ARB
Network
Rx
Tx
SRQ
IFC
56833
DE02
IRQ
ACIA
IP
CIA-2
IEEE
PWR
56834
DE03
Data Direction Register For DEOO
56835
UtU4
Data Direction Register For DE01
OOOOO
IRQ
ACIA
IP
CIA-2
IEEE
PWR
OOOOf
DE06
CB
CA
Graphics
IRQ
stack On
56838
DE07
Active Interrupt Register
56839
6525 Tri Port 2
DFOO
Keyboard
57088
DF01
Select
57089
DF02
CRT
Mode
Keyboard Read
57090
DF03
Data Direction Register for DFOO (out)
57091
DF04
Data Direction Register for DF01 (out)
57092
DF05
Data Direction Register for DF02 (in)
57093
DF06
Unused
57094
Figure C.14
214
MACHINE LANGUAGE FOR COMMODORE MACHINES
COMMODORE 128:
Memory Maps
These maps apply to the machine when used in the 1 28K mode. When
used in the 64 mode, the machine's map is identical to that of the Com-
modore 64. Since the RAM work area is 7K in size — as compared to the
Commodore 64 with 1 K — the map can be huge; it is somewhat abridged
here.
Architecture: "Bank numbers" as used in BASIC BANK and the MLM
addressing scheme are misleading; in fact, they are more correctly "con-
figuration numbers." Banl< shows RAIVI level 0, which contains work
areas and the user's BASIC program. Bank 1 also shows RAM, this time
(for addresses above hexadecimal □^□□) level 1 which contains vari-
ables, arrays, and strings. Other "banks" are really configurations, with
various types of ROM or I/O overlaying RAM. Thus, Bank 15 (the most
popular) is ROM and I/O covering RAM bank 0. Bank 14, however, is
ROM and the character generator overlaying RAM Bank 0. Architecture
Is set so that addresses below $ □ □ reference Bank only. Other bank
switching (more complex than the simplified 16-bank concept) is accom-
plished via storing a mask to address $FFDD, or calling up prestored
masks by writing to $FFD1-FFD4.
The Great Zero-Page Hunt:
Locations $FA to $FF are available. Locations $EA to $2C, $50 to
$55, and $5'^ to $tS are work areas available for temporary use.
Most zero-page locations may be copied to another part of memory so
that their original contents can be restored after use. The programmer
should take great care, however, in modifying the following locations, which
are critical within the operating system or BASIC: $15, $lfl to $1A,
$5D to $3E, $5t to $57, $10 to $^A, $A0 to $65, $A7 to $Afl,
$BA to $BE., $BD, $CD, $Cfl to $Dfl.
APPENDIX C — COMMODORE 128
215
Memory Map
ALL BANKS:
Hex
Decimal
Description
□ □□0
□
I/O directional register
□ DDI
1
I/O port, similar to C64
□ □□5-
■QUDA
2-4
SYS address, MLM registers
(SR, PC)
□ □□5-
■□□□q
5-q
SYS, MLM register save (A, X,
Y, SR/SP)
OODA
1^
Scan-quotes flag
□ □□B
11
TAB column save
□ □□C
12
□ = LOAD, 1= VERIFY
□ OOD
13
Input buffer pointer/number of
subscripts
□ □□E
lA
Default DIM flag
□ □□F
15
Type: FF = string; □□ = numeric
□ □ID
It
Type: fl □ = integer;
□ □^floating point
□ □11
17
DATA scan/LIST quote/memory
flag
□ □IB
Ifl
Subscript/FNx flag
□ □13
iq
□ = INPUT;$4D = GET;
$'=ifl = REaD
QUIA
2^
ATN sign/Comparison
evaluation flag
□ □15
21
Current I/O prompt flag
□ □It-
■□□17
22-23
Integer value
□ □Ifl
24
Pointer: temporary string stack
□ □IR-
■□□53
25-35
Stack for temporary strings
□ □E4-
•□□27
3b-3q
Utility pointer area
□ □5fl-
□ DEC
AU-AA
Product area for multiplication
□ □5D-
■□□2E
AS-Ah
Pointer: start-of-BASIC (for
Bank 0)
□ □BF-
■□□3^
A7-Aa
Pointer: start-of-variables
(Bank 1)
□ □31-
■□□32
A^-SD
Pointer: start-of-arrays
□ □33-
■UU3A
51-52
Pointer: end-of-arrays
□ □35-
■□□3t
53-54
Pointer: string-storage (moving
down)
216
MACHINE LANGUAGE FOR COMMODORE MACHINES
Hex
Decimal
Description
□ D37-
□ □3fl
55-5b
Utility string pointer
oaaq-
■□□3a
57-5fl
Pointer: limit-of-memory
(Banl< 1)
□ □3B-
■□□3C
5q-tD
Current BASIC line number
□ □3D-
•□□3E
Textpointer: BASIC work point
□ □3F-
■QUAQ
ys-yA
Utility Pointer
■UDAS
t5-tt
Current DATA line number
□ □^3-
■QOAA
t7-tfl
Current DATA address
■□□<t
tq-7a
Input vector
□
■QQA&
71-72
Current variable name
■UDAh.
73-74
Current variable address
OUAB-
■nuAC
75-7t
Variable pointer for FOR/NEXT
■UUAE
77-7fl
Y-save; op-save; BASIC pointer
save
□ □^F
7<=\
Comparison symbol
accumulator
□ □5D-
-□□55
fl^-flS
Miscellaneous work area,
pointers, and so on
□ □5t-
-□□5fl
flt-flfl
Jump vector for functions
□□5q-
-□□EdE
flq-qfl
Miscellaneous numeric work
area
□ □t3
qq
Accum#1 : exponent
-□□t7
1^^-1D3
Accum#1 : mantissa
□□ta
IQA
Accum#1: sign
1^5
Series evaluation constant
pointer
-□□tF
l^b-111
Accum#2: exponent, and so on
□□?□
112
Sign comparison, Acc#1 versus
#2
0D71
113
Accum#1 lo-order (rounding)
□ D72-
-□□73
114-115
Cassette buffer len/Series
pointer
□ □74-
-□□75
llfc-117
Auto line number increment
□ □7t
llfl
Graphics flag
□ □77
iiq
Color source number
□ □7fl-
12^-121
Temporary counters
□□7a-
-□□7C
125-124
DS$ descriptor
□ □7D-
-□□7E
155-lSt
BASIC pseudo-stack pointer
QQ&A
132
Multicolor 1 (1)
□ □fl5
133
Multicolor 2 (2)
APPENDIX C — COMMODORE 128
277
Decimal
uGscnpuon
□□at
13A
Graphic foreground color (13)
□
lAA
Status word ST
IAS
Keyswitch lA: STOP and RVS
flags
□ □•=15
lAh
Timing constant for tape
nn^A
1A&
Serial output: deferred
character flag
lA^
Serial deferred character
DDH?
151
Rogister sdve
□ □Sfl
152
How manv nnpn filp^
ODRR
153
Inmit rip\/icp nnririAllv/ H
II i|JLii U9vi\/C) iiuiiiiciiiy \J
□ □Hft
154
Outnut OMD Hpvirp nnrmallv ^
\./ui|>/ui Vi/iviL^ uwviv^Oj iiuiiiiciiiy w
ODRB-
155-
-15ti
Tnnp nflHtw oi itni it-rpppi\/pH
ffaa
□ □qD
157
I/O iTiPQQAnPQ' — all
ti^=6rrors n = nil
tJ ^ ^1 1 Wl 0, LJ 1 III
u Lj n ij
LI LJ n X
15fl-
-15R
M _J 1
Tonp prrrtr nointorc
I a\JKS CIIUI jJvlllLOlO
□ □an-
LJ LJ n LJ
-nn A?
LJ LJ n ^
ItD-
-ItE
.liffv/ ninrk HMI
uiiiy wivwiv niviL.
□ □ft3-
□ DAB
JI O -J
□ DAC-
■□OAD
175-
■173
Pnintpr* tanp huffpr ^prollinn
1 VII 1191 ■ iCl|i^o UUIIwl) OwlWIIIIIU
□ □AE-
•DDAF
174-
•175
Tanp pnri arlri^/Fnd nf nrnnrain
■ m|m/9 91 IU CllJlJO/ IU \Jl UIWMIGllll
□ □BD-
■ODBl
17t-
■177
Taoe timino constants
ODBa-
■□□B3
17a-
■17R
Pointer' start of tanp huffpr
1 Wll ILwl ■ wlCtl i wl ICIUv UUIId
DDB7
las
Number of characters in file
I I ■ WV^I Wl IW»I WtWlwl III 1 II W
name
□ DBA
16A
Current logical file
□ DBS
las
Current secondary address
OQBA
Iflb
Current device
VI 1 1 \^ III V 1
ODBB-
■□□BC
167-
•laa
Pointer to file name
1 will Iwl iw 1 llw 1 ICil 1 Iw
□ DBD-
■00C5
laq-
•1^7
1/0 worl< pointers
□ DCt-
□ DC?
iRa-
•iqq
Banks: I/O data, filename
□ □Cfl-
•QDCB
EQQ-
•ED3
RS-232 input/output buffer
addresses
□ □cc-
□ OCD
^DA-
ED5
Keyboard decode pointer (Banl<
15)
□ □CE-
□ OCF
2Db-
ao7
Print string work pointer
□ □DD
EQ&
Number of characters in
keyboard buffer
QODl
Number of programmed chars
waiting
218 MACHINE LANGUAGE FOR COMMODORE MACHINES
nsx
Decimal
uescnpuon
□ DDE
Programmed key character
index
□ DD3
511
Key shift flag: □ = no shift
□ □D^
5ia
Key code: 88 if no l<ey
□ 0D5
213
Key code: 88 if no l<ey
□ □Dt
214
Input from screen/from
keyboard
ODD?
215
40/80 columns: □ = 40 columns
□ □Dfl
21t>
Graphics mode code
□ DDI
21?
Character base: D = ROM,
4 = RAIVI
DDDA-
DDDF
21fi-
223
Misc work area
DDEQ-
ODEl
224-
225
Pointer to screen line/cursor
□ □E2-
DDEB
EEb-
227
Color line pointer
22a
Current screen bottom margin
LJ LJ XJ -J
22"=l
Current screen top margin
□ □Et
23D
Current screen left margin
DDE?
231
Current screen right margin
DDEfl-
DDEq
232-
233
Input cursor log (row, column)
DDEA
234
End-of-iine for input pointer
DDEB
235
Position of cursor on screen
line
DOEC
23t>
Row where cursor lives
DDED-
□ □EE
23?-
■23fl
Maximum screen lines, columns
DDEF
23q
Current I/O character
DDFD
24D
Previous character printed
DDFl
241
Character color
DDF3
243
Screen reverse flag
DDF4
244
D = direct cursor; else
programmed
DGF5
245
Number of INSERTS
outstanding
DOFt
24t
255= Auto Insert enabled
DDF?
24?
Text mode lockout
DOFfl
24fl
D = Scrolling enabled
DDFq
24q
Bell disable
DDFA-
□ DFF
25D-
255
Not used
□ IDD-
□ IFF
25t-
511
Processor stack area
OlDD-
D13E
25t-
31fl
Tape error log
APPENDIX C — COMMODORE 128
219
Hex
Decimal
Description
UJ U. LI LJ
LJ L- n LI
515
-b75
BASIC inDut buffer
ur^^^i^y II ii^ui uui iwi
LJL.nL—
■ □P AE
LJ L. n ij
h7A
Bank nppk subroutine
Lf n i.
U L~ U U
tfl7
-7D1
Rrink nnkp ^iihrnutinp
LJ t JJ JJ
■ UPCC
LJ t ^
7UE
-71b
Rank nnmnarp Qiihrnutinp
LJCll iT\ wWI 1 lla/Cll w OUUIWUIIIIC
U C JJ IZ
717
-73fl
.I5^R tn annthpr hank
U t U J
LJ U. X JJ
73'^
-7t)3
.IMP tn annthpr hank
UIVII L\J Cll Iwll Id Udl lr\
7t<
-7t5
Fiinr^tinn pypputP hnnk
^*|/ ^ ^ 1 LI J
ninri-
LJ -J LJ LI
LI -J LJ JJ
7tfl
-7t'^
^rrnr mp^Qanp link
^1 1 LJI 1 1 ICOOQMw III lr\
rr^n?-
LI J LI L.
LI J LI J
770
-771
RA5^in warm ^tart link
ur^oi V-/ vvcii 1 1 1 oicii I III ir\
LI J LJ ^
LJ J LI J
775
-773
Crunrh RA5^IC tnkpn^ link
ui ivi 1 ujrwjt\j i\Ji\vi lo III ii\
Q3Uh-
D307
774
-775
Print tokens link
1 1 11 li Iw III lf\
Q3U&-
D30R
77Ea
-777
Start new BASIC code link
i 1 IwVV L^rAWI^y wWUw III li\
Lf J LI n
LI -J U U
77fl
-771
f^pt arithmptir pipmpnt link
V^vl mI III II 1 IwLIV/ wlwlllwlll III ll\
LI J LI
LI J LI
730
-7fll
Orunrh FF hook
\yi UI Iwl 1 1 ^ 1 IWf\
□ 3DE-
□ 3DF
755
-7fl3
List FE hook
^Iwl 1 ^ 1 lwUI\
□ 31D-
□ 311
7&A
-7fl5
Fypouta FE hook
□ 313-
LJ ^ M Im.
□ 313
7&h
-7fl7
LJnuspd
\Jl 1 LiO^\J
Q31A-
0315
76e>
-76"=!
IRQ vector fFAtSl
□ 31t-
0317
7R0
-711
Break interrunt vector FBCin^l
LJ -J JJ LI
LI J JJ 1
7'^5
-713
NMI intprriint vprtor fFA^ni
I^IVII II HOI 1 LI|.Jl VwL^lLJI [X n ^ LJ J
□ 31A-
031B
LJ _J JJ U
7'=\A
-715
OPEN Vector FEFBDl
□ 31C-
031D
7Rt
-717
CLOSE vector FFlflfll
^^^^^W^ V-wwlwl 1 X JI LJ UJ
031E-
LJ _J JJ 0-1
n3iF
LJ 1 ^ J.
7^5
-711
Rpt-innrjt vprtnr rFiriPil
Wd II l|JLIL VCL^ILJI [X JJ LJ nj
n3?n-
LI J ^ LJ
□ 3P1
LJ — J ^ JJ
flOD
-fl^l
5^pt-ONtnut vprtor FFIi^Pl
Wwl L/Ull<^UL VwwlWI [X XI ^
LJ J t ^
n3P3
LJ J ^ J
fl05
-603
Rp^torp l/n \/prtor FFPPtil
riCOlUiw l/w VCOIL/I [X L. DJ
LI J ^ *n
n3P^
LJ J Urn J
flD4
-fl05
Inntit vprtnr rFFfirnl
IIIULIl VCL^ILJI L LI uJ
□ 3Et-
LJ 1^ 1
ant
-flD7
Outnut vprtnr FEF?^!
Vi^Ul^Lil Vv/wlVJI l,XJ X 1 IJ
□ 3Efl-
□ 3ER
flOfl
-ADR
Test-STOP Vector TFttEl
1 CO I W 1 ^^1 V vvlvl 1 X D D ^ J
□ 3EA-
□ 3EB
fllO
-All
GET vector FEEEBl
LJ _J l_
□ 3PD
\-l —J \— Ly
fll5
-fll3
Abort I/O vertor FFPPPl
□ 32E-
035F
&IA
-fll5
Machine Lang Monitor link
□ 33D-
□ 331
filt
-fll7
LOAD link
D33e-
0333
fiia
-an
SAVE link
□ 334-
□ 335
fiEQ
-flEl
Control code (low) link
□ 33t-
□ 337
fl55
-fl35
High ASCII code link
□ 33fl-
□ 33q
fl54-
-fl55
ESC sequence link
□ 34A-
□ 353
&AE
-351
Keyboard buffer
0354-
□ 35D
fl55-
-fltl
Tab stop bits
□ 35E-
□ 3bl
at,5-
-flt5
Line wrap bits
220 MACHINE LANGUAGE FOR COMMODORE MACHINES
Bank 0:
Hex
Decimal
Description
LJ -J □ ^
LI J D U
LI u □ LI 1 ^
Lnniml filp tahip
LI J 1 ^
LI 1 □ LI LI ^
r)p\/irp niimhpr t^hlp
•n37P
LI _J 1 X
LJ LJ □ LJ n ^
RpponHprv aHHtpqc tAhIp
U J LJ u
LI J I Xj
LI n o n ^ □
HHRfiFT mihrniitinp
□ 3flt
ROE
CHRGOT entrv
□ 3RF-
■D3AR
RE7-'13a
Fetch from RAM Bank
1 W i W 1 1 II III 1 1 1 V 1 ^^l>4l 1 |\ ^/
LJ ^ n u
LJ .J U O
R3R-R5D
Fetch from RAM Bank 1
□ 3B7-
■D3BF
Fetch from RAM Bank 1
□ 3CD-
•03Ca
Fetch from RAM Bank
U J 1
\J 3 U Ji
pfnCi— q77
F^trh frnm RAM RanW
LI -J 1^ ^
LJ U 1/ ^
R7 A-q AD
n 1 LI n LJ LI
[ IniiQPH
U -J 1/ Z3
q Ai.
n LI ^
CJiirrpnt RANK for <?Y9 PFFK
LJ -J J-l Li
qq4
Granhin/Tpxt harknrnunriQ
\Jti CI|<Ji iiv/ 1 CAl liyClL/i\MI wUi lUO
u J ri J
~ n J
^rsnhi^/Mi liti r^oinr Inn
ci|ji iiwiviuiii ouiUi luy
J. X LI u
D ^ ^ LJ U
MMI I pnnfini irfltinn rpniQfpr
IVIIVIL^ L/UI III^LJI ClliLJI 1 IC^lOlv?!
X X LI -U
± X LI ^
t5Efll-t5Efl4
MMLI load cnnfin reaistpr^
LI *n LI U
LI 1 J-l 1
XILI^^ ^LIL.^
4.0-rnlijmn ^rrppn mpmorv
V/U 1 LI 1 1 1 1 1 Owl C^l 1 1 1 Iwl 1 l\Jl y
U f X X
I^IJ*~ILJ t^Ll^i
^nritp idpntitv flrPA ^tpvt^
W|<^l lie ILlwl iiiiy Cll cci yicAiy
nflnri-
LI LI U LJ
LJ 1 X X
pnz A_pqt,n
RA55IO n^Pudo-Qtank
nnnr
pq7P
^ ^ 1 L.
OA A 1 intpmint Inn
Wlr^ 1 II lid I U^l
□ ADD
LI n LI J-/
E573
CIA 1 timer enabled
\i/lfl 1 til I Iwl wl lUh^lwVI
LJ n LI X
t_i n jj 1
5575-E5fi3
^ — 1 1 J ^ ^ LI ^
RS-232 work values
□fiifl
E5fl4
RS-232 receive Dointer
LI n jj n
pq Aq
^ ^ LI ^
RS-Pf^P innut nnlntpr
1 ivJ ^\J^ III^Ul ^WilllUI
□ filA
Esat
RS-232 transmit pointer
□ filB
E5a7
RS-232 send pointer
□ AID-
•OAIF
E5aa-E5qo
Sleeo countdown"
FFFF = disable
X X X X UlwQUIw
U rl Li
pqqp
C J 1 L.
Kpvhnard huffpr ^i7p
IXwyl^L^ClIU ia^LJIld Ol^v7
n fl p 1.
U n C Jl
c ^ n J
.Qcrppn frpP7P flan
□ fl55
Esq^i
Key repeat: 1 E a = all,
t< =none
□ flE3
Esqs
Key repeat timing
□ A2<
Esqt
Key repeat pause
□ AEB
S5q7
Graphics/text toggle latch
□ RPt
S5qa
40-col cursor mode
□ fi27-
□ REa
Esqq-EfcDE
40-col blink values
OfiEB
EtD3
80-col cursor mode
□ fiEC
EbD<
40-col video $DDia image
APPENDIX C — COMMODORE 128
221
Hex
Decimal
Description
-□ASF
-5tD7
80-coI pages — screen, color
□ fi^D
-□ftSfi
Eb5<
-5b50
40/80 pointer swap $EO-Fa
□ AbO
-□AtD
-EtfcH
40/80 data swap $354-3tl
□acD
5752
PAT counter
□ ACl
-□AC<
5753
-575fc
ROM Physical Address Table
□ BDO
-□BBF
5filb
-3007
Cassette buffer
OCOG
-□DFF
3075
-3533
RS-232 input, output buffers
□EDD
-□FFF
3534
-40q5
System sprites ( 5 1 - 1 3 )
-IDQq
4oqt
-4105
Programmed key lengths
IDDA
-IDFF
-4351
Programmed key definitions
lino
-1130
<355
-4400
DOS Command staging area
1131
-llbE
AAUl
-44t5
Graphics work area
lltF
Trace mode: FF=on
117D
-1173
-44b7
Renumbering pointers
117^
-1177
AAhd,
-4471
Directory work pointers
117fl
-11H7
AA7E
-4473
Graphics index
117a
-117B
AAIA
-4475
Float-fixed vector [34 RF]
117C
-117D
AA7\3
-4477
Fixed-float vector [7R3C]
117E
-11D5
AAlb
-45ti5
Sprite motion tables (8x11
bytes)
llDb
-11E5
45tt
-4531
Sprite X/Y positions
llEt
4535
Sprite X-high positions
11E7
-llEfl
4533
-4534
Sprite bump masks (sprite,
backgnd)
llER
-llEA
4535
-453t
Light pen values, X and Y
llEB
4537
CHRGEN ROM page, text [DB]
llEC
4538
CHRGEN ROM page, graphics
[DO]
llED
45Bq
Secondary address for
RECORD
llEE
-IIFF
45qo
-4t07
Unused
lEUA-
-1E07
4tl5
-4bl5
PU characters ( / . $)
1506-
-ISDC
4tlR
-4b5D
TRAP address: F FFF if none
lElD-
-lEll
4t54
-4b55
End of BASIC
iei5-
-1513
4t5b
-4t,57
Basic program limit [FFOO]
1E14-
-1S17
4b5B-
-4t31
DO work pointers
151fl-
-lElfi
4t35-
-4t34
USR program jump [7D5B]
151B-
-151F
4t35-
-4t3q
RND seed value
1E5E
4t45
Sound tempo
laEF
4t55
Music sequencer
222
MACHINE LANGUAGE FOR COMMODORE MACHINES
Hex
Decimal
Description
Bank 1 :
0^00-
Bank 14: Same as
DDDD-
Bank 15:
DDOO-
DADD-
D5DD-
1EB7 Ai,i.D-Ai,y3 Note image
1E3E AhL5-Ai,7Q Current env pattern
1E7D <t71-<7en Envelope tables ..
Ah71-Ah&Q AD(SR) pattern
1552 <tfll-<tqD (AD)SR pattern
1E5C <tqi-<70D Waveform pattern
lEtb <7D1-';;71D Pulse width pattern
1E70 ^711-^720 Pulse widtli hi pattern
1E74 Note: xx.xx.volume
4 7 E 5 Previous volume image
lE7a <7Eb-47Efl Collision IRQ task table
1E7E A7?'^-A73A Collision IRQ address tables
4735 Collision mask
473b Collision work value
47 as PEN work value
A&kA-LlAB Unused
tl44-71fc7 Reserved for key functions
71bfl-fc4511 BASIC RAM memory (text)
71ta-fllflfc Video (color) matrix (hi-res)
aia7-aiqi Sprite identities (hi-res)
aiq5-lt3a3 Screen memory (hi-res)
Ib3a4-b4511 BASIC RAM memory (hi-res)
Basic variables, arrays, strings
Character generator ROM
ROM: BASIC
40-col videa chip 8564
SID sound chip 6581
Memory Management Unit
8722
DfcOO-DtDl 547a4-547a5 80-column CRT controller 8563
DaD0-DaE7 55EHt-5tEq5 Color nibbles
DCDD-DCDF 5t3ED-5fc33t CIA 1 (IRQ) 6526
DDDD-DDDF 5t57fc-5t5qi CIA 2 (NMI) 6526
DFDQ-DFDR 57Daa-570qa DMA slot
EDOO-FEFF 57344-t5E7q ROM: Kernal
FFD5-FFFF b5Ea5-t5535 ROM: Transfer, Jump Table
1E34-
lE3q-
1E3F-
1E3F-
1E53-
1E5D-
lEb7-
1E71-
1E75
lE7b-
lE7q-
1E7F
lEao
ISBl
13DD-
laoD-
ICDO
ICDD-
IFFB-
EDOD-
4D00-
17FF
IBFF
FBFF
1FF7
IFFF
3FFF
FBFF
FBFF
Bank 15,
DFFF
CFFF
DOEE
D41C
D50A
lDE4-b4511
below, except:
53E4a-57343
It3a4-53E47
53E4a-53Eq4
54E7E-543DD
545Ea-5453fl
APPENDIX C — COMMODORE 128
223
8502 Processor I/O registers
0000
xxxxx
0=in
1=out
= in
1=out
1=out
1=out
1=0lll
00000
0001
xxxxx
Caps
Key
Tape
Motor
Tape
Sense
Taps
Outpt
HiRes
LoRes
Color
Acces
00001
Figure CIS
224
MACHINE LANGUAGE FOR COMMODORE MACHINES
CI 28 Memory Map
8564 Video — Sprite Registers
Sprite
Sprite
Sprite Sprite
7
7
0000
DOOE
Position
X_
53248 53262
D001
OOOF
Y
53249 53263
0027
D02E
Color
53287 53294
Sprite Bit Positions
7 6 5 4 3 2 1
001
X-position liigh
53264
O015
Sprite Enable
53269
0017
Y-expand
53271
001 B
Bacl<ground Priority
53275
001 C
i\^uiticoior
53276
0010
X-expand
53277
001 E
interrupt: Sprite coiiisn
53278
001 F
interrupt: Sprite/Bacl<grd coil
53279
Figure C.I 6
APPENDIX C — COMMODORE 128
225
C128 Memory Map
D011
D012
D013
0014
8564 Video —
Control and Misc. Registers
Extnd Color
Bit Map
Dsply EnabI
Row Selct .
A
Y-Scroll
Raster Register
Light Pen Input
X
Y
S3265
53266
53267
53268
D016
X
Reset
Multi Color
Colm Sel .
A
X-Scroll
53270
D018
Screen (Video Matrix)
vm13 vm12 vm11
vm10
Character Base
cb13 cb12 cb11
X
53272
D019
IRQ
IRQ sence
LP 1 SSC 1 SBC
RST
53273
D01A
IRQ Enable
Light Collision
Pen , Sprt , Back
Rastr
53274
COLOR REGISTERS
0020
Exterior
53280
0021
Bacl(ground #0
S32B1
0022
Background #1
53282
0023
Background #2
53283
0024
Background #3
53284
0025
Sprite Multicolor #0
53285
O026
Sprite Multicolor #1
53286
D02F
xxxxx
xxxxx
xxxxx
xxxxx
xxxxx
[Keyboard Rows]
53295
0030
xxxxx
xxxxx
xxxxx
xxxxx
xxxxx
xxxxx
Test
Fast
Clock
53298
Figure C.I 6 continued
226 MACHINE LANGUAGE FOR COMMODORE MACHINES
SID (6581) Commodore 128
V1
U40U
D401
V2
V3
VI V2 V3
U4U/
D408
U'fUt
D40F
— Frequency
1
H
<^4^>79 *;497Q 'i4.Pftfi
54273 54280 54287
D402
D409
D410
Pulse Width
L
54274 54281 54288
D403
D40A
D411
H
54275 54282 54289
D404
D40B
D412
Voice Type
NSE 1 PUL 1 SAW 1 TRI
KEY
1 1 1
54276 54283 54290
D405
D40C
D413
Attacl<
Time
2ms-8sec
1 1 1
Decay
Time
6ms-24sec
1 1 1
54277 54284 54291
D406
D40D
D414
Sustain
level
1 1 1
Release time
6ms-24sec
1 1 1
54278 54285 54292
Voices
(write only)
D415
L
54293
D416
Filter Frequency
H
54294
D417
Resonance F'"®'' voices
, , , |eXT, V3 , VJ , V,
54295
D418
Passband
V3 1
OFF 1 HI 1 BD 1 LO 1
Master
Volume
1 1 1
54296
Filter & Volume
(write only)
D419 Paddle X 54297
D41A Paddle Y 54298
D41B Noise 3 (random) 54299
D41C I Envelope 3 ~| 54300
Sense
(read only)
Special voice features (TEST, RING MOD, SYNC) are
omitted from the above diagram.
Figure C.17
APPENDIX C — COMMODORE 128 227
Memory Management Unit 8722
DSOO
RAM select
0-3
HIGH RAM
/ROM
MID RAM
/ROM
LO
RAM
CGEN
54S28
DS01
-D504
Preconfiguratlon registers;
Similar to DSOO, above
54529
-54532
D50S
40/80
Key
C64
Mode
Cartr-Sense
Color-Bank
Fast
Disk
xxxxxxxxxxx
280
54533
D506
Video-Bank
xxxxxxxxxxx
Shared RAM
hi knv
Shared RAM
1K
54534
D507
D508
L
H
Zero page pointer
($0000)
54535
54536
D509
D50A
L
H
Stack page pointer
($0100)
54537
54538
Figure C.I 8
228 MACHINE LANGUAGE FOR COMMODORE MACHINES
8563 CRT Controller
D600 read (status):
D800
Status
Ught
Pen
Vert
Blank
xxxxxxxxxxxxxxxxxxxxxxxxx
54784
D600
54784
□601
54785
Value
$00
Horizontal Total
126
1 $01
Horizontal Characters Displayed (80)
80
2 $02
Horizontal Sync position
102
3 $03
Sync WIdtli
Vertical Horizontal
1/3
4 $04
xxxxx 1 Vertical Total
32 or 39
5 $05
xxxxx xxxxx xxxxx 1 Vertical Total Adjust
6 $06
xxxxx
Vertical Displayed (25)
25
7 $07
xxxxx
Vertical Sync Position
29 or 32
8 $08
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Interlace
9 $09
xxxxxxxxxxxxxxxxx
Scan Lines per Character
7
10 $0A
xxxxx 1 Cursor Mode
Cursor Start
32
1 1 $0B
xxxxxxxxxxxxxxxxx
Cursor End
7
12 $0C
13 $0D
xxxxxxxxxxx
Display H
Address L
14 $0E
15 $0F
Cursor Address H
L
16 $10
17 $11
Light Pen H
Input L
varies
varies
18 $12
19 $13
Video RAM Address H
(See register 31) L
varies
varies
20 $14
21 $15
Color H
Address L
B
22 $16
Character
Total C
)isplay Horizontal
Display Vertical
120
g
23 $17
xxxxxxxxxxxxxxxxx
24 $18
Blocl<
Copy
Born
RVS
Blink
Rate
V Scroll
32
25 $19
Bit
Map
Color
Enable
Semi
Graphic
Wide
Pixel
H Scroll
64 or 71
26 $1A
Color
Foreground Background
240
27 $1B
Scroll Control Horizontal
28 $1C
Char set address
RAM 1 xxxxxxxxxxxxxxxx
32
29 $1D
xxxxx xxxxx xxxxx
Underline Scan Line Count
7
30 $1E
Character Count
varies
31 $1F
32 $20
33 $21
Video RAM data (see registers 18,19)
varies
varies
varies
Block Copy Start H
Address L
34 $22
35 $23
Display begin
Enable end
125
100
36 $24
xxxxxxxxxxxxxxxxxxxxxx 1 DRAM refresh rate
S
Figure C.19
APPENDIX C — COMMODORE 128
229
CIA 1 (IRQ) (6526) Commodore 128
Paddle SEL
A , B
R 1
Joystick
L , D
1 u
$DCOO
Keyboard Row Select (Inverted)
PRA 56320
Joystick 1
$DC01
Keyboard Column Read
PRB 56321
$DC02
$FF —
All Output
DDRA 56322
$00 —
All Input
UUnb ODOfO
!pUuU4
$DC05
Timer A
TAL 56324
TAH 56325
$DC06
$DC07
Timer B
TBL 56326
TBH 56327
$DCOC
Serial (shift) Register
56332
$DCOD
IRQ
xxxxxxxxxxx
Rag
S.Reg
xxxxx
TIm.B
Tlm.A
56333
$DCOE
S Reg
I/O
Timer A
ToggI
56334
Load
0/S
Start
$DCOF
Timer B
56335
Load
0/S
Start
Figure C.20
230 MACHINE LANGUAGE FOR COMMODORE MACHINES
CIA 2 (NMI) (6526) Commodore 128
$DDOO
Serial
In
Clock
In
Serial
Out
Clock
Out
ATN
Out
1 1
RS-232
Out
1 1
Video
Block
PRA
56576
$DD01
DSR
In
CTS
In
DCD*
In
Rl*
In
DTR
Out
RTS
Out
RS-232
In
PRB
56577
Parallel User Port
$DD02
In
In
Out
Out Out
$3F
Out
Out
Out
DDRA
56578
$DD03
$06 For RS-232
DDRB
56579
$DD04
$DD05
Timer A
TAL
TAH
56580
56581
$DD06
$DD07
Timer B
TBL
1 bn
56582
56583
$DDOD
RS-232
In
Timer
B ,
Timer
A
ICR
56589
$DDOE
Timer
, A Start
CRA
56590
$DDOF
Timer
, B Start
CRB
56591
Figure C.21
DMA Controller
DFOO
Busy
Fault
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
57088
DF01
Exec
Sum
xxxxxxxxxxx
IRQ
Inc
Mode
57089
DF02
Host
L
57090
DF03
Address
H
57091
DF04
Expansion
L
57092
DF05
Address
H
57093
DF06
xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Expansion Bank
57094
DF07
Transfer
L
57095
DF08
Length
H
57096
DF09
Checksum
57097
DFOA
Version, MaxImum-IVIemory
57098
xxxx = unused
(blank) = not of interest
Figure C.22
APPENDIX C — COMMODORE 128
231
Commodore 64: ROM Detail
This type of ROM memory map is intended primarily for users who want
to "browse" through the inner logic of the computer. It allows a user to
disassemble an area of interest, to see why the computer behaves in a
certain way. With the use of this map, the user will be able to identify
subroutines that are called by the coding under study.
I recommend against using the ROM subroutines as part of your own
programs. They often don't do precisely what you want. They change
locations when you move to a different machine. With rare exceptions,
you can probably write better coding to do the job yourself. Stick with the
kernal jump table: especially $FFDa to output; $FFE4 to get input;
$FFE1 to check the RUN/STOP key; $FFCfc and $FFCR to switch
input and output respectively; and $FFCC to restore normal input/output.
They are the same on all Commodore computers.
aODO : ROM control vectors
ft □ □ C : Keyword action vectors
ft □ 5 2 : Function vectors
A □ fl □ : Operator vectors
ROSE: Keywords
RIRE: Error messages
ft 3 E a : Error message vectors
ft 3 Ea 5 : Miscellaneous messages
ft3flft : Scan stack for FOR/GOSUB
ft 3 B a : Move memory
ft 3 F B : Check stack depth
kAD6: Check memory space
ft^ 3 5 : Print "out of memory"
ft^37: Error routine
ft^tq: BREAK entry
HAIA: Print "ready . "
kA&Q: Ready for BASIC
ft^ SC : Handle new line
ft533 : Re-chain lines
ft5 b : Receive input line
ft57'1: Crunch tokens
fttl3: Find BASIC line
ftb<2: Perform [NEW]
fttSE: Perform [CLR]
fttaE : Back up text pointer
fttqC: Perform [LIST]
232
MACHINE LANGUAGE FOR COMMODORE MACHINES
Perform [FOR]
a 7 E D : Execute statement
RAID : Perform [RESTORE]
aaec: Break
RflEF: Perform [STOP]
Rfl31: Perform [END]
aa57: Perform [CO NT]
afl71: Perform [RUN]
aflflB: Perform [GOSUB]
aaaO: Perform [goto]
aflDE: Perform [RETURN]
aflFfi: Perform [b a T A]
a'=1 1 : Scan for next statement
aqafl: Perform [IF]
aR3B: Perform [REM]
aq^B: Perform [ON]
an bB : (3et fixed point number
aqa5: Perform [LET]
aaaO: Perform [PRINT#]
aaat: Perform [CMD]
aaaO: Perform [print]
aBlE : Print string from (Y.A)
aB 3 B : Print format cliaracter
aB^D : Bad input routine
aB7B: Perform [GET]
KBkS: Perform [INPOT#]
aBBF: Perform [INPUT]
aBFR : Prompt and input
aCDt: Perform [RE ao]
aCFC : Input error messages
RDIE : Perform [NEXT]
aD7 a : Type match cfiecl<
aDRE : Evaluate expression
aEaa: Constant-pl
aEFl: Evaluate witliin bracl<ets
aEF7 : Check for " ) "
aEFF : Check for comma
aFOa: Syntax error
AFIA : Check range
aF 2 a : Search for variable
aFR7 : Set up FN reference
aFEfc: Evaluate [OR]
APPENDIX C — COMMODORE 1 28 233
RFEq: Evaluate [AND]
BDlfc: Compare
BDfll: Perform [DIM]
B □ a B : Locate variable
B 1 1 3 : Check alphabetic
BHD: Create variable
B 1 R 4 : Array pointer subroutine
BIAS: Value 3E7ta
BIBE: Float-fixed
BlDl: Set up array
BE AS: Print "bad subscript"
B a ^ fl : Print "illegal quantity"
B3AC: Compute array size
B37D: Evaluate [F RE]
B3R1: Fixed-float
B3qE: Evaluate [POS]
B3fit: Checl< direct
B3B3: Perform [DEF]
B3E1: Checl< fn syntax
B3F4 : Evaluate [FN]
BAhS: Evaluate [ST R$]
BA7S: Calculate string vector
B^fi?: Set up string
BAFA: Make room for string
B 5 E t : Garbage collection
B 5 B D : Check salvageability
BhDh: Collect string
Bti3D: Concatenate
B 1 7 ft : Build string to memory
Btft3 : Discard unwanted string
BtDB : Clean descriptor stack
BfcEC: Evaluate [CHR$]
B7 00: Evaluate [LEFT$]
B7 2C: Evaluate [RIGHT$]
B737: Evaluate [MID $]
B7bl : Pull string parameters
B77C: Evaluate [L EN]
B7 a E : Exit string-mode
B7aB: Evaluate [AS C]
B 7 R B : Input byte parameter
B7AD: Evaluate [?AL]
B7EB : Parameters for POKE/WAIT
234
MACHINE LANGUAGE FOR COMMODORE MACHINES
B7F7:
Float-fixed
BfiDD:
Evaluate [PEEK]
BflE< :
Perform [POKE]
BflED:
Perform [WAIT]
Bfl^R:
Add □ . 5
BflBD:
Subtract-from
Bfl53:
Evaluate [subtract]
BflbA:
Evaluate [add]
B^A7 :
Complement FAC (floating accumulator)*!
BS7E:
Print "overflow"
Bqfl3:
Multiply by zero byte
B^ER:
Evaluate [LOG]
BAEB:
Evaluate [multiply]
Multiply-a-bit
BRflC:
Memory to FaC#E
BRB7:
Adjust Fac#l and FaC#S
BAD<:
Underflow/overflow
BAEE:
Multiply by 1 □
BAPq:
+ 1 □ in floating point
BRFE:
Divide by ID
BBIE:
Evaluate [divide]
BBRE
: Memory to FAC#1
BBC7
: FRC#1 to memory
BBFC
: FRC#E to FRC#1
BCDC
: FRC#1 to FRC#S
BCIB
: Round FAC#1
BCEB
: Get sign
BC3q
: Evaluate [SGN]
BC5fi
: Evaluate [RBS]
BC5B
: Compare FRC#1 to memory
BCqB
: Float-fixed
BCCC
: Evaluate [INT]
BCF3
: String to FRC
BD7E
: Get ASCII digit
BDCE
: Print "IN.."
BDCD
: Print line number
BDDD
: Float to ASCII
BFlt
: Decimal constants
BF3A
: TI constants
BF71
: Evaluate [SQR]
BF7B
: Evaluate [power]
BTBA
: Evaluate [negative]
APPENDIX C — COMMODORE 128 235
Dr riU .
bvaiuate L'C>a1:'J
£1 U A d .
Series evaluation 1
1? n c Q •
Series evaluation E
T? n a *7 •
tvaiuate [kndj
JiUr n .
Kernal calls with error checking
rertorm [SYSJ
£1 Jj 3 b .
renorm [oAVrij
rerform [VERIrij
171 C- A •
rerrorm liiUiiiJj
17 1 m7 •
£iJiD£i .
rertorm lUriiNj
£iJjL r .
rertorrn [CLObEj
171 T\/' •
rararneters lor LUAU/oiiVrii
17 3 n C- •
£iCUb .
Check default parameters
17 3 rrp •
Check for comma
17 3 1 □ •
Parameters for open/close
IT 3 t_ /■ •
evaluate [LUbj
17 3 r D •
evaluate [bi Nj
3 K y •
evaluate [TAN]
evaluate lATNj
1737R •
vvarm resian
17 3 Q y* •
Initialize
3 7\ 3 •
Jcid Ac :
c tin GET tor zero page
"C 3 D17 •
Initialize basic
Vectors for $ 3
P /■ C 3 •
riH 3 d .
Initialize vectors
17/" C17 •
Power-up message
17 q n n •
£1 3 U U .
vaet i/u aaoress
17 c n c •
£i3U3 .
Get screen size
pen n •
£1 3 U ti .
rui/gei row/coiumn
17 C 1 A -
Initialize l/U
17 C /" /" •
Clear screen
17 c: L L •
£1 3 b b .
nome cursor
P C (L P •
£1 3 b L .
Set screen pointers
17 C 7\ n -
£i b U .
bet i/u detauits
JJ ^ U *-| •
Inniit frr»m I^A\/Kr\orH
lll[JUl IIUIil ISc^yUQafU
Eb3E:
Input from screen
ELfl^ :
Quote test
Etqi :
Set up screen print
EbBb :
Advance cursor
EtED :
Retreat cursor
E701:
Back into previous line
236
MACHINE LANGUAGE FOR COMMODORE MACHINES
E 7 1 1 : Output to screen
Efi7C: Go to next line
EflU: Perform (return)
EfiRl: Check line decrement
EflBB: Check line increment
EflCB: Set color code
E fl D a : Color code table
EflER: Scroll screen
ERtS: Open space on screen
ERCfl : Move a screen line
Synchronize color transfer
E =1 F □ : Set start-of-line
EHFF : Clear screen line
EA13: Print to screen
EA54 : Synchronize color pointer
Ea31 : Interrupt-clock, etc.
Eaa?: Read keyboard
E B 7 ■=! : Keyboard select vectors
E B fi 1 : Keyboard 1 -unshifted
E B C 2 : Keyboard 2-shifted
ECD3 : Keyboard 3-"Commodore" shift
'ECAA: G raphics/text contrl
E C ^ F : Set graphics/text mode
EC7fl: Keyboard 4
ECBH : Video chip setup
ECE7 : Shift/run equivalent
ECFD : Screen In address low
EDDR: Send "talk" to serial bus
EDDC : Send "listen" to serial bus
□ : Send to serial bus
EDBE: Serial timeout
EDBR: Send listens a
EDBE : Clear aTN
EDC7: Send talks a
EDCC : Wait for clock
EDDD : Send serial deferred
EDEF : Send "untalk" to serial bus
EDFE : Send "unlisten" to serial bus
EE13 : Receive from serial bus
EEflB: Serial clock on
EEflE: Serial clock off
EEq7: Serial output "1"
EEaD: Serial output "0"
APPENDIX C — COMMODORE 128
237
EEfiR :
oc^iial III aiiu olUUK olynalS
EEB3 :
Dplflv/ 1r miIIiQPr»nnrl
L^^icty ju 1 1 11 1 iioc7\/Ui lU
J— I -LJ U Lj ■
EFOt :
fipnrl npu/ RQ-P'^P h\/to
EF5E :
Nn-D 9 R prrnr
INU i-/ O IV ClIUI
EF31 •
I^HJ ^ X O OllUl
EF3B •
r^icsKIp timpr
L^iodUlc? llllim
EF<fl :
Comnutp hit rnunt
EF5R :
no ^Oi£. fCyUclVc
RF7F •
U i. 1 U •
oci U|J lu iC/Uc^lVc
EFC5 :
Rpppiwp naritv/ prrnr
EFCR :
Rppipwp n\/prflA\A/
ricVi/icvc uvciiiuw
EFCD :
Rpppi\/p Krpsil^
nci^dvc uiccif\
FFnn •
nidiiiiiiu ciiui
EFEl :
Submit to RS-232
Fnnn •
1. LJ LJ X/ •
INU JJ O Ja ciiUi
r u jj r >
QpnH tn DQ OQO hnff^^r
OcllQ lO riO'dO^ DUUQT
FD^D :
Inniit frnm RQ-OQO
iii|jui iiuiii no jco^
FOflt :
Get from R55-P'^P
Vi^wl II \J* II 1 iw
FOAA :
Gheok ^prifll hii^ IHIp
wl lwwf\ O^l ICli k/UO ILIIC?
FDBD :
Messaops
FIEB:
Print if direct
1 1 II 1 1 ■ ■ Villi W \J I
F13E :
Get
Fl^^E :
from
• • • II Ul 1 1 1
F157 :
Inni it
Fiqq •
tnPt' tartp/cprial/QQ.O'^O
FlCft :
Outniit
FIDD :
tn tsnp
FEDE :
^pt inniit Hp\/ipp
FE50 :
Sst outnut ripvirp
FERl :
ninQP flip
wiWOC IIIC7
F30F :
Find filp
1 II lU 1 1 1 w
F31F:
Set file values
^^\^ ^ III V W^l U V'W '
F35F :
Abort all filp^
fiwwl I will iliww
F333 :
Rp^torp HpfAiilt I/O
F3^ft:
Do file ooen
lll\^ ^^I^V^I 1
F3D5 :
Send SA
F40q:
Open RS-232
F4SE:
Load program
FSftF:
Print "searching"
F5C1:
Print filename
F5Da:
Print "loading/verifying"
F5DD:
Save program
238
MACHINE LANGUAGE FOR COMMODORE MACHINES
FbfiF :
Print "saving"
Ft'lB :
Bump clocl<
FtBC :
Log PI a l<ey reading
FbDD :
Get time
FtE4 :
Set time
FtED :
Ciieci< stop key
FfcFB :
Output error messages
F72D :
Find any tape header
F7bR :
Write tape header
F7DD :
Get buffer address
F7D7 :
Set buffer start/end pointers
F7ER :
Find specific header
FflDD :
Bump tape pointer
Ffil7 :
Print "press play . . ."
FflSE :
Checl< tape status
Ffl3fl :
Print "press record . . ."
Ffl^l :
Initiate tape read
Fflt^ :
Initiate tape write
Ffl75
Common tape code
FflDO
Check tape stop
FflEE
; Set read timing
FREC
: Read tape bits
FftbD
: Store tape characters
FBflE
: Reset pointer
FBR7
: New character setup
FBat
: Send transition to tape
FBCfl
: Write data to tape
FBCD
: IRQ entry point
FC57
: Write tape leader
FCH3
: Restore normal IRQ
FCBfl
: Set IRQ vector
Fcca
: Kill tape motor
FCDl
: Check R/W pointer
FCDB
: Bump R/W pointer
FCE2
: Power reset entry
FDDE
: Check fl-ROM
FDin
L 1/ ^ LJ
fi-ROM mask
FD15
: Kernal reset
FDia
: Kernal move
FD3a
: Vectors
FD5D
: Initialize system constants
FDqB
: IRQ vectors
FDa3
: Initialize I/O
APPENDIX C
— COMMODORE 128
23d
FDDD
: Enable tirner
FDFR
: Save filename data
FEDO
: Save file details
FED?
Get status
FElfl
: Flag status
FEIC
: Set status
FE51
: Set timeout
FE25
Read/set top of memory
FE27
Read top of memory
FEED
Set too of msmorv
FE34
Read/^et bottom of memorv
FE<3
NMI entry
FEtt
Warm start
FEBt
Reset IRO and exit
FEBC
InterruDt exit
ill fcwl 1 Mil/ I V«/\l 1
FEC5
RS-232 timing table
FEDt
NMI RS-232 in
FFQ7
NMI RS-232 out
Fake IRQ
FF^fl
IRQ entry
FFfll
Jumbo jump table
FFFA
: Hardware vectors
D
Character
Sets
241
242 MACHINE LANGUAGE FOR COMMODORE MACHINES
Superchart
The "superchart" shows the PET character sets. A byte may have any of
several meanings, depending on how it is used. The chart is constructed
to reflect this. "ASCII" is PET ASCII; these are the characters as they
would be input or printed. "Screen" is the Commodore screen codes, as
they would be used in screen memory— POKE ing to or PEEKing from
the screen would yield these codes. Notice that the numeric character set
is the same for both screen and PET ASCII.
Within a program, the code changes again. "BASIC" shows these codes;
they are similar to ASCII in the range $ED to $5F.
Machine language op codes are included for the sake of convenience and
completeness.
DECIMAL
HEX
ASCII
SCREEN
BASIC
6502
DECIMAL
00
@
end-line
BRK
1
01
A
ORA(l,X)
1
2
02
B
2
3
03
C
3
4
04
D
4
5
05
white
E
ORAZ
5
6
06
F
ASLZ
6
7
07
bell
G
7
8
08
locl<
H
PHP
8
9
09
unlock
1
ORA#
9
10
OA
J
ASLA
10
11
OB
K
11
12
OC
L
12
13
OD
car ret
M
ORA
13
14
OE
text
N
ASL
14
15
OF
top
15
16
10
P
BPL
16
17
11
cur down
Q
ORA(l),Y
17
18
12
reverse
R
18
19
13
cur home
S
19
20
14
delete
T
20
21
15
del. line
U
ORA Z,X
21
22
16
ers.begin
v
ASL Z,X
22
23
17
w
23
24
18
X
CLC
24
25
19
scr. up
Y
CRAY
25
26
1A
z
26
27
IB
[
27
28
1C
red
\
28
29
ID
cur right
1
ORAX
29
APPENDIX D — SUPERCHART
243
ECIMAL
HEX
ASCII
SCREEN
BASIC
6502
DECII
30
1E
green
T
ASLX
30
31
IF
blue
31
32
20
space
space
space
JSR
32
33
21
!
!
1
AND(I,X)
33
34
22
It
"
"
34
35
23
#
#
#
35
36
24
$
$
$
BITZ
36
37
25
%
%
%
ANDZ
37
38
26
&
&
&
ROLZ
38
39
27
,
f
f
39
40
28
(
(
(
PL
40
41
29
)
)
)
AND#
41
42
2A
*
*
*
ROLA
42
43
2B
+
+
+
43
44
2C
1
■
1
BIT
44
45
2D
AND
45
46
2E
ROL
46
47
2F
/
/
/
47
48
30
BMI
48
49
31
1
1
1
AND(I),Y
49
50
32
2
2
2
50
51
33
3
3
3
51
52
34
4
4
4
52
53
35
5
5
5
AND Z,X
53
54
36
6
6
6
ROL Z,X
54
55
37
7
7
7
55
56
38
8
8
8
SEC
56
57
39
9
9
9
ANDY
57
58
3A
CLI
58
59
3B
59
60
3C
<
<
<
60
61
30
_
—
-
ANDX
61
62
3E
>
>
>
ROLX
62
63
3F
?
?
?
63
64
40
@
B
@
RTI
64
65
41
A
1, a
A
EOR(l,X)
65
66
42
B
m, b
B
66
67
43
C
S,c
C
67
68
44
D
e, d
68
69
45
E
B,e
E
EORZ
69
70
46
F
B.f
F
LSRZ
70
71
47
G
U.g
G
71
72
48
H
n, h
H
PHA
72
73
49
1
Q, i
EOR#
73
74
4A
J
13. j
J
LSRA
74
75
4B
K
H, k
K
75
76
4C
L
m
L
JMP
76
77
4D
M
M
EOR
77
78
4E
N
la, n
N
LSR
78
244 MACHINE LANGUAGE FOR COMMODORE MACHINES
DECIMAL
HEX
ASCII
SCREEN
BASIC
6502
DECI
79
4F
Co
79
80
50
P
P
P
BVC
80
81
51
Q
1, q
Q
EOR(l),Y
81
82
52
R
B. r
R
82
83
53
S
ffl, s
S
83
84
54
T
Ct
T
84
85
55
U
Q, u
U
EOR, Z,X
85
86
56
V
H, V
V
LSR Z,X
86
87
57
w
P. w
w
87
88
58
X
1. X
X
CLI
88
89
59
Y
y
Y
EOR Y
89
90
5A
z
1, z
z
90
91
5B
[
m
[
91
92
5C
\
B
\
92
93
5D
]
]
EORX
93
94
5E
T
a, s
T
LSRX
94
95
5F
«—
«-
95
96
60
□
RTS
96
97
61
n
ADC(I,X)
97
98
62
B
98
99
63
□
99
100
64
□
100
101
65
D
ADCZ
101
102
66
RORZ
102
103
67
□
103
104
68
PLA
104
105
69
EM
ADC#
105
106
6A
□
ROR A
106
107
6B
107
108
6C
a
JMP(I)
108
109
6D
s
ADC
109
110
6E
a
ROR
110
111
6F
a
111
112
70
s
BVS
112
113
71
H
ADC(I),Y
113
114
72
a
114
115
73
m
115
116
74
c
116
117
75
D
ADC Z,X
117
118
76
a
ROR Z,X
118
119
77
□
119
120
78
n
SEI
120
121
79
□
ADCY
121
122
7A
122
123
7B
□
123
124
7C
a
124
125
7D
H
ADCX
125
126
7E
B
RORX
126
127
7F
IS
127
APPENDIX D — SUPERCHART
245
DECIMAL
HEX
ASCII
SCREEN
BASIC
6502
DECI^
128
80
r-@
END
128
129
81
orange
r-A
FOR
STA(I,X)
129
130
82
r-B
NEXT
130
131
83
r-C
DATA
131
132
84
r-D
INPUT#
STYZ
132
133
85
r-E
INPUT
STA Z
133
134
86
r-F
DIM
STX Z
134
135
87
r-G
READ
135
136
88
r-H
LET
DEY
136
137
89
r-l
GOTO
137
138
8A
r-J
RUN
TXA
138
139
8B
r-K
IF
139
140
8C
r-L
RESTORE
STY
140
141
8D
car ret
r-M
GOSUB
STA
141
142
8E
graphic
r-N
RETURN
STX
142
143
8F
bottom
r-0
REM
143
144
90
black
r-P
STOP
BCC
144
145
91
cur up
r-Q
ON
STA(I), Y
145
146
92
rvs off
r-R
WAIT
146
147
93
clear
r-S
LOAD
147
148
94
insert
r-T
SAVE
STYZ,X
148
149
95
ins. line/br
r-U
VERIFY
STA Z,X
149
150
96
ers. end/p
r-V
DEF
STX Z,Y
150
151
97
Gray 1
r-W
POKE
151
152
98
Gray 2
r-X
PRINT#
TYA
152
153
99
scr. down
r-Y
PRINT
STA Y
153
154
9A
L. Blue
r-Z
CONT
TXS
154
155
9B
Gray 3
r-[
LIST
155
156
9C
magenta
r-\
CLR
156
157
9D
cur left
r-]
CMD
STA X
157
158
9E
yellow
r-t
SYS
158
159
9F
cyan
r-*- ,
OPEN
159
160
AO
■
CLOSE
LDY #
160
161
A1
C
r-l
GET
LDA(I,X)
161
162
A2
H
{-"
NEW
LDX #
162
163
A3
n
r-#
TAB(
163
164
A4
□
r-$
TO
LDYZ
164
165
A5
□
r-%
FN
LDA Z
165
166
A6
s
r-&
SPC(
LDX Z
166
167
A7
□
r-'
THEN
10/
168
A8
r-(
NOT
TAY
168
169
A9
B. &
r-)
STEP
LDA#
169
170
AA
□
r-*
+
TAX
170
171
AB
IE
r- +
171
172
AC
a
r-,
*
LDY
172
173
AD
H
r-
/
LDA
173
174
AE
S
r-.
T
LDX
174
175
AF
a
r-/
AND
175
176
BO
Q
r-O
OR
BCS
176
246 MACHINE LANGUAGE FOR COMMODORE MACHINES
DECIMAL
HEX
ASCII
SCREEN BASIC
6502
DECIMAL
177
B1
H
r-1
>
LOA(l),Y
177
178
B2
S
r-2
=
178
179
B3
m
r-3
<
179
180
B4
c
r-4
SGN
LOY Z,X
180
181
B5
r-5
INT
LOA Z,X
181
182
B6
□
r-6
ABS
LDX Z,Y
182
183
B7
n
r-7
USR
183
184
B8
n
r-8
PRE
CLV
184
185
B9
□
r-9
POS
LOA Y
185
186
BA
a,
r-;
SQR
TSX
186
187
BB
a
r-;
RND
187
188
BC
a
r-<
LOG
LOYX
188
189
BD
ffl
r- =
EXP
LOAX
189
190
BE
D
r->
COS
LDX Y
190
191
BF
B
r-?
SIN
191
192
CO
B
TAN
CPY#
192
193
CI
k, a
ATN
CMP(I),X
193
194
C2
m, b
PEEK
194
195
C3
8. c
LEN
195
196
C4
e. d
STR$
CPYZ
196
197
C5
H, e
VAL
CMPZ
197
198
C6
a, f
ASC
DECZ
198
199
C7
DD, g
CHR$
199
200
C8
DD, h
LEFT$
INY
200
201
09
S, i
RIGHTS
CMP #
201
202
CA
MID$
DEX
202
203
CB
ffl, k
GO
203
204
CC
D, 1
CONCAT
CPY
204
205
CD
IS, m
OOPEN
CMP
205
208
CE
Z, n
DOLOSE
DEC
206
207
CF
n,
RECORD
207
208
DO
a.p
HEADER
BNE
208
209
D1
1, q
COLLECT
CMP(I),Y
209
210
D2
g, r
BACKUP
210
211
D3
1, s
COPY
211
212
D4
n, t
APPEND
212
213
05
Q, u
DSAVE
CMP Z,X
213
214
06
H, V
OLOAD
DEC Z,X
214
215
07
1, w
<^ ATA 1 rt/^
CATALOG
215
216
D8
H, X
RENAME
CLO
216
217
09
□l.y
SCRATCH
CMP Y
217
218
DA
l.z
DIRECTORY
218
219
08
m
219
220
DC
E]
220
221
bo
n
CMP X
221
222
OE
s, a
DEC X
222
223
OF
i
223
224
EO
CPX#
224
225
El
Li
SBC(I).X
225
APPENDIX D — SUPERCHART
247
DECIMAL
HEX
ASCII
SCREEN BASIC
i5502
DEC!
226
E2
C3
226
227
E3
■
227
228
E4
■
CPX Z
228
229
c5
■
SBC Z
229
230
E6
n
m
INC Z
230
231
E7
■1
■1
231
CO
CO
B
INX
232
233
E9
B. m
SBC #
233
■I
NOP
234
235
CD
CD
D
235
cU
CPX
236
cU
li
SBC
237
OOO
Zoo
BC
cc
■■
P
INC
238
00&
cc
cr
B
239
Oil A
rU
D
Bed
240
0>l 4
C4
Pi
El
SBC(I), Y
241
o>io
CO
H
242
OilO
243
CO
r3
'.a
243
Oil il
244
p4
n
244
Oyl C
240
ro
rm
n
Sou Z,X
245
240
Cfi
ro
W
INC Z,X
246
247
F7
1
247
248
F8
i
BED
248
249
F9
H
SBC Y
249
250
FA
l.B
250
251
FB
9
251
252
FC
B
252
253
FD
B
SBCX
253
254
FE
a
INCX
254
255
FF
IB IT
255
248 MACHINE LANGUAGE FOR COMMODORE MACHINES
Control Character Representations
NUL
Null
DLE
Data Link Escape (CC)
SOH
Start of Heading (CC)
DC1
Device Control 1
STX
Start of Text (CC)
DC2
Device Control 2
ETX
End of Text (CC)
DCS
Device Control 3
EOT
End of Transmission (CC)
DC4
Device Control 4
ENQ
Enquiry (CC)
NAK
Negative Acknowledge (CC)
ACK
Acknowledge (CC)
SYN
Synchronous Idle (CC)
BEL
Bell
ETB
End of Transmission Block
BS
Backspace (FE)
(CC)
HT
Horizontal Tabulation
CAN
Cancel
(FE)
EM
End of Medium
LF
Line Feed (FE)
SUB
Substitute
VT
Vertical Tabulation (FE)
ESC
Escape
FF
Form Feed (FE)
FS
File Separator (IS)
-» CR
Carriage Return (FE)
GS
Group Separator (IS)
SO
Shift Out
RS
Record Separator (IS)
SI
Sfiift In
US
Unit Separator (IS)
DEL
Delete
(CC)
Communication Control
(FE)
Format Effector
(IS)
Information Separator
Figure D.I
Special Graphic Characters
^SP
Space
-» <
Less Than
I
Exclamation Point
— > =
Equals
-»"
Quotation Marks
-» >
Greater Than
^#
Number Sign
Question Mark
^$
Dollar Sign
Commercial At
^%
Percent
->[
Opening Bracket
-»&
Ampersand
\
Reverse Slant
1
Apostrophe
^]
Closing Bracket
^(
Opening Parenthesis
Circumflex
^)
Closing Parenthesis
Underline
. *
Asterisk
Grave Accent
Plus
{
Opening Brace
Comma
1
Vertical Line (This graphic
Hyphen (Minus)
is sometimes stylized to
Period (Decimal Point)
distinguish it from the un-
Slant
broken Logical OR which
Colon
is not an ASCII character)
»
Semicolon
}
Closing Brace
Tilde
Characters marked -» correspond to the PET ASCII character set.
Figure D.2
APPENDIX D — ASCII
249
ASCII
ASCII is the American Standard Code for Information Interchange. It is
the standard for communications, and is often used with non-Commodore
printers.
When a Commodore machine is in its graphic mode, its character set
corresponds closely to ASCII. Numeric, upper case alphabetic, and punc-
tuation characters are the same. A few control characters, such as
RETURN, also match. Commodore graphics have no counterpart in ASCII.
When the Commodore machine is switched to text mode, the character
set diverges noticeably from ASCII. Numeric characters and much of the
punctuation corresponds, but ASCII upper case alphabetic codes match
the Commodore computer's lower case codes. Commodore's upper case
alphabetics are now completely out of the ASCII range, since ASCII is a
seven-bit code.
As a result. Commodore's PET ASCII codes require conversion before
transmission to a true ASCII device or communications line. This may be
done with either hardware interfacing or with a program. Briefly, the pro-
cedure is:
1 . If the Commodore character is below $ 3 F , it may be transmitted directly to
the ASCII facility.
2. If the Commodore character is between S-^ D and $5F, it should be logically
OEed with $BD (or add decimal 35) before transmission to ASCII.
3. If the Commodore character is between $00 and $DF, it should be logically
RNDed with $7F (or subtract decimal lEfl)before transmission to ASCII.
Equivalent rules can be derived to allow a Commodore computer to receive
from ASCII. For either direction of transmission, some control characters
may require special treatment.
250 MACHINE LANGUAGE FOR COMMODORE MACHINES
First Hexadecimal Digit
(0
1
2
3
4
5
6
7
NUL
DLE
SP
@
P
P
1
SOH
DC!
!
1
A
Q
a
q
2
STX
DC2
2
B
R
b
r
3
ETX
DC3
#
3
C
S
c
s
4
EOT
DC4
$
4
D
T
d
t
5
ENQ
NAK
%
5
E
U
e
u
6
ACK
SYN
&
6
F
V
f
V
7
BEL
ETB
t
7
G
w
g
w
8
BS
CAN
(
8
H
X
h
X
9
HT
EM
)
9
1
Y
y
A
LF
SUB
*
J
z
j
z
B
VT
ESC
+
t
K
(
k
{
C
FF
FS
<
L
\
1
1
1
D
CR
GS
M
]
m
}
E
SO
RS
>
N
n
F
SI
US
/
?
DEL
ASCII code values.
E
Exercises for
Alternative
Commodore
IVIacliines
251
252 MACHINE LANGUAGE FOR COMMODORE MACHINES
Commodore 128 users should turn to page 257.
From Chapter 6:
VIC-20 (Unexpanded) Version
We write the BASIC program as follows:
!□□ V%=0
IIU F0RJ = 1T0 5
12D INPUT "VALUE"
130 SYS + + + +
IAD PRINT "TIMES TEN ="
150 NEXT J
Plan to start the machine language program at around <0R7 + 127,or
AEEA (hexadecimal IQflO). On that basis, we may change line 130 to
SYS 4 E 54. Do nof try to run the program yet.
A loao
LDY
#$05
a lOflE
LDA
($5D) ,
Y
A IQ&A
STA
$033C
A IDfi?
STA
$D33E
A lOfiA
LDY
#$03
A lOflC
LDA
($5D),
Y
A loaE
STA
$033D
A loqi
STA
$D33F
A loq^
ASL
$033D
A lOq?
ROL
$033C
A loqA
ASL
$D33D
A ID^D
ROL
$D33C
A lOAO
CLC
A lOAl
LDA
$D33D
A 10A4
ADC
$033F
A IDA?
STA
$D33D
A IDAA
LDA
$033C
A lOAD
ADC
$D33E
A lOBO
STA
$□330
A 10B3
ASL
$033D
A lOBL
ROL
$0330
A IGBR
LDY
#$□5
A IGBB
LDA
$0330
A IDBE
STA
($5D) ,
Y
A IDCO
LDY
#$□3
A iDca
LDA
$033D
A 1DC5
STA
($5D),
Y
A 10C7
RTS
APPENDIX E — PET/CBM VERSION
253
To change the start-of-variables pointer to a location above the machine
language program, display the SOV pointer with .M DDSD DDEE and
change the pointer to
:DDED Cfl ID
PET/CBM Version
We write the BASIC program as follows:
!□□ V^=D
110 F0RJ = 1T0 5
150 INPUT "VfiLUE"
130 SYS + + + +
IAD PRINT "TIMES TEN = " ;
150 NEXT J
Plan to start the machine language program at around lDS5 + 127,or
1155 (hexadecimal <flO). On that basis, we may change line 130 to
SYS 1155. Do noMry to run the program yet.
A
O-^flO
LDY
#$05
A
LDA
($5A),
Y
A
DA&A
STA
$033C
A
UA&7
STA
$D33E
A
UA&k
LDY
#$03
A
UA&C
LDA
($5A),
Y
A
OA&B
STA
$033D
A
o^qi
STA
$033F
A
o<q/;
ASL
$033D
A
o^q?
ROL
$033C
A
D^qA
ASL
$033D
A
D^qD
ROL
$D33C
A
D^AO
CLC
A
O^Al
LDA
$033D
A
O^A^
ADC
$033F
A
0<A7
STA
$033D
A
D^AA
LDA
$033C
A
O^AD
ADC
$033E
A
O^BO
STA
$033C
A
QAB3
ASL
$D33D
A
D<Bt
ROL
$033C
A
D^eq
LDY
#$05
A
D^BB
LDA
$033C
A
D^BE
STA
($5A),
Y
254 MACHInI language FOR COMMODORE MACHINES
ft QACD LDY #$03
A DACE LDft $D33D
ft QiSGS STft ($EA),Y
ft Qi^C? RTS
To change the start-of-variables pointer to a location above the machine
ikhguage program, display the SOV pointer with M DDSft DDSB and
change the pointer to
iDUEk Cfl D< . .
From Chapter 7:
An Interrupt Project
VIC-20 (Unexpanded) Version
The only difference with the VIC-20 is that the screen is located at $ IE □ □ :
ft D33C LDft $qi
ft 033E STft $1EDD
A Q3A1 JMP ($D3ftD)
To place the link address into $D3ftD/l:
ft niAA LDft $Q31A
ft Q3A7 STft $03ftD
ft 034ft LDft $0315
ft 034D STft $03ftl
To fire up the program:
ft 0350 SEI
ft 0351 LDft #$3C
ft 0353 STft $0314
ft 035t LDft #$03
ft d35fl STft $0315
ft 035B CLI
ft D35C RTS
To restore the original interrupt:
A D35D SEI
ft D35E LDA $03AD
A D3tl STA $0314
A D3Ed4 LDA $03A1
A D3t7 STA $0315
APPENDIX E — PET/CBM VERSION
255
A dafcft CLi
a 03tB RTS
SYS fl3t will Invoke the new Interrupt code; SYS flbl will turn it off. As
with the Commodore 64, there is a possibility of the character printing
white-on-white, so that it cannot be seen.
PET/CBM Version
This version is not for original ROM machines, which have the IBQ vector
located at address SDEl'^/A:
a 0330 LDa $qB
a □33E STa $flDDD
a nsAi JMP ($D3aD)
To place the linl< address into $D3aD/l:
a niAA LDa SDoqa
a 03^7 STA $D3Rn
a D34a LDa $dqri
a U3AB STa $03ai
To fire up the program:
a 0350 SEI
a 0351 LDa #$3C
a 0353 STa IDDRD
a 035^ LDa #$D3
a 0356 STa $no<=]i
a 0358 CLI
a D35C RTS
To restore the original interrupt:
a □35D SEI
a □35E LDa $03aD
a □3bl STa $OQRD
a Q3hA LDa $D3ai
a D3t7 STa $Doqi
a Q3yA CLI
a DStB RTS
SYS fl3t will invoke the new interrupt code; SYS flbl will turn It off.
Since the PET/CBM does not have colors, the characters will always show.
256 MACHINE LANGUAGE FOR COMMODORE MACHINES
1
Project: Adding a Command
PETICBM Version
It's not possible to write a comparable program to add a command to the
PET/CBM. This machine doesn't have a "link" neatly waiting for us at
address $030fi/R. Equivalent code would need to be somewhat longer
and less elegant.
The equivalent program for PET/CBM won't be given here. It would involve
writing over part of the CHRGET program (at $□□?□ to $0Dfl7), sup-
plying replacement cdde for the part we have destroyed, and then adding
the new features.
APPENDIX E — EXERCISES FOR THE C128
257
Exercises for the Commodore C1 28
From Chapter 1:
Locations $0360 and $ 0361 are important in the CI 28. Tiiey are sen-
sitive BASIC locations, and if we changed them, BASIC would stop worl<-
ing. So we'll change the task to this: swap the contents of locations $ □ B fl □
and $DBfll.
Our plan will lool< lil<e this:
LDA $aBfiD (bring in first value)
LDX $DBai (bring in second value)
STA $DBfil (store In opposite place)
STX SDBfiD (and again)
BRK
We may write the machine language code as:
AD fiO DB LDA $DBQO
AE fll OB LDX $OBfll
flD fll OB STA SDBfll
flE flO DB STX $DBflD
□ BRK
The code within the computer will consist of 13 bytes: AD flO DB AE fll
DB flD fll DB flE flD DB DO. Now we decide where to put it.
On the Commodore 1 28, we can't use the addresses starting at $ □ 3 3 C—
we'd quici<ly run into sensitive areas. We'll place our program into the
C128's cassette buffer that starts at address $DBDD (decimal El flit).
That's a good place to put short test programs on this machine, and most
of our following examples will go there.
On the Commodore 128, the BASIC command MONITOR will bring the
machine language monitor into action. You'll immediately get the register
display:
MONITOR
PC SR AC XR YR SP
; FBDDD DD DD DD DD Pq
The cursor will be flashing at the start of the next line.
The information is as explained in chapter 1 , except that the address under
PC contains an extra digit. The first digit (in this case, the "F") is called
Vn^ank number. The letter F is hexadecimal notation for the value 15
decimal, and we say that the program stopped in bank 15 at address hex
BDDD.
258
MACHINE LANGUAGE FOR COMMODORE MACHINES
For the moment, we can consider that "bank 15" means "situated in
ROM— Read Only Memory." We l<now that the iVIachine Language Monitor
is built into the Commodore 128; so of course it's in ROM.
When we write programs, we will put them in RAM. The Commodore 128
has a great deal of RAM fitted to it. We could choose RAM from bankO,
where BASIC programs are stored, or from bank 1, where BASIC vari-
ables, arrays and strings are kept. There's plenty of memory in either
bank. We will choose bank 0, mostly because it's easier— if the first digit
is zero (for bank 0) we don't have to type it.
To display memory from $lDDOto$lDlDwe would command:
M 1000 1010
The resulting memory display might look something like this:
>1D0D 07 Dt OA 07 Ob 04 05 Dfl:
>lDDfl Oq 05 A7 5E Al 50 A& A"^: . .GRAPHI
>1D1Q A3 AA AC AT Al AA 22 44 :CDLOAD"D
The four-digit number at the start of each line represents the address in
memory being displayed. The two-digit numbers to the right represent the
contents of memory. The characters to the right of the colon are ASCII
equivalents of the same memory contents (or a period if no equivalent
exists). If you are working on an 80-column monitor, you will get more
memory locations per line than are shown above.
To change memory, we move the cursor until it is positioned over the
memory contents in question, type over the value displayed, and then
press RETURN. You can't change the ASCII part of the display; only the
two-digit hexadecimal values.
If you have displayed the contents of memory, as in the example above,
you might wish to change a number of locations. Be careful: on the Com-
modore 128, this particular part of memory holds the definitions for the
function keys, F1 to F10. The first ten bytes are definition lengths; the
following locations, as you might have guessed, are the definitions them-
selves. If you play with these locations, expect to end up with muddled
function keys.
Here comes our final rewrite of this program example:
DBOO AD flO DB LDA SOBflO
OBOB AE fil OB LDX $OBfll
OBOb aD fll OB STA $OBfll
DBOq fiE flO DB STX $DBflO
OBOC 00
Now to put it in:
APPENDIX E — EXERCISES FOR THE C128
259
We go to the MLM, and display memory with
M BDD BDC
Note that we may drop leading zeros. The first address in full is □□BDD
(banl< D, address DBD D). But we may shorten it if we wish; in either case,
we'll get something like:
>DDBDD XX XX XX XX XX XX XX XX :
>DDBDfl XX XX XX XX xx xx xx xx:
l\^ove the cursor back and change this display so that it looks like this:
>DDBDD AD flD DB AE ai OB flD fll:
>DDBDa DB flE flD DB DD XX XX XX :
Don't type in the "xx" or the trailing colon or periods— just leave whatever
was there before. And be sure to press RETURN. If you have an 80-
column display, you will get the whole memory display on one line.
Now we must put something into locations $DBfiDand$DBaiso that
we'll know that the swap has taken place correctly.
Display memory with M BfiD Bfll and set the resulting display so that
the values are
>DDBaD 11 R"^ XX XX XX XX xx xx
Remember to press RETURN. Now we may run our program; we start it
with
G BDQ
Display the data values to confirm that they have been exchanged with
M 03&0 D361.
From Chapter 2:
Print projects:
The first exercise uses the same code, but is placed in address B^^:
A DBDD LDA #A&
Note that the use of the dollar sign for hexadecimal is optional in this
monitor. It's probably better to use it, but if you don't the computer will
assume hex numbers are intended. Using the plus sign to signal a decimal
number, you could type . . .LDA # + 75 and the decimal value of
7 S — the same value as hex < fi— will be accepted. You could even type
. . . LDA #^D1DD1DDD to enter the same number in binary. Either
way, it's still the ASCII letter H, and you'll find that hexadecimal is more
convenient and compact.
If you have correctly typed the line, it will be assembled. The object code
will be placed into memory starting at the address specified and you'll also
260
MACHINE LANGUAGE FOR COMMODORE MACHINES
see it on the screen as part of the line that you originally typed. You'll also
get a prompt for the next instruction. The screen will now show:
ft DDBDD Aq ^fl LDfi#$^fl
ft QDBDS
The cursor will be flashing to the right of the "5." Continue by typing in
JSR $FFD5 and pressing RETURN. Again, the computer will rework
what you have typed and anticipate your next line by printing ft DDBDS,
which allows you to type in the final command, BBK. The screen now
looks like this:
RDDBDDAq^fl LDR #$<fl
ft QUEUE EU DE FF JSR $FFD2
ft DDBDB □□ BBK
ft ODBOb
Press RETURN to signal that you're finished. If you wish, you may display
memory with M BDO BOt. You'll see your program in memory:
>DDBOD ftq 50 DE FF OD xx xx
There's less need to check your work with a disassembler since you can
see the code as it is being written. But it never hurts to be safe; so we
may inspect our program again with:
D BUU BUS
Note that we give two addresses, the starting and the ending address. If
you give the starting address only, you'll get about 20 bytes of code, which
is more than we need.
If you wish to disassemble more code than the screen will hold, you may
"continue" a disassembly by typing the letter D by itself. You'll get about
20 more bytes from wherever your previous disassembly left off. Inciden-
tally, you can use the same technique for memory display: an M command
without an address will continue a memory display.
Minor errors that you spot in either an assembly or a disassembly may
be corrected directly on the right-hand side of the assembly or disassembly
listing. In other words, suppose that you had incorrectly coded LD ft # $ 5 fl
during the assembly phase; when you perform the disassembly, this line
will show as
□ □BDD 5fl LDft#$5fi
You recognize that the $58 should be $48; you may move the cursor up—
use cursor home if you wish— and type over the value on the right-hand
side. In this case, you place the cursor over the 5, type A to change the
display to and press RETURN. You will see from the display that
the problem has been fixed.
To run the program type the command G FDBOD. What? Our program
is in bank 0; how can we call it by naming bank 15? And why would we
do so?
APPENDIX E — EXERCISES FOR THE C128
261
We can successfully call the program by naming bank 15 for this reason:
in bank 15, all addresses below hexadecimal AUDU (decimal lh3&A)
are taken from RAN, bank 0. It would be more accurate to call bank 15,
"configuration 15." You can read more on this, when you're ready, in
Appendix B-1 . That explains how we get there; but why bother?
We need to call bank 15 because our program calls CHROUT at address
$FFD5— a ROM routine. And we see ROM in bank 15, not in bank 0. If
we were in bank and made a subroutine call to address $FFD2, we'd
jump to RRM at that address. There's no code at that location in RAM,
and we'd be in trouble.
When you get into advanced programming in the Commodore 128, you
will be able to call subroutines across banks. At that time, you'll be able
to have a program running in bank zero that will call a subroutine in ROM,
bank 15, with provision for a successful return to bank zero. When you're
ready for it, you'll find that a subroutine called JSFAR, located at address
$02CD in all banks, will do the job of getting you across and back. You'll
need to learn how to carefully set up the contents of addresses E to fl
before calling JSFAR.
For the moment, we can skip the advanced techniques and get our pro-
gram running with G FQBDD. The H will be printed on the same line, to
the right of the last zero.
To switch this program to a BASIC-callable subroutine, we must change
the BRK command at the end to an RTS. Disassemble, if you wish, and
type over the BRK with the characters RTS.
Just before returning to BASIC, let's ask for the decimal equivalent to
hexadecimal QBOD. Type $BDD and press return. You'll see the equiv-
alent representations in hexadecimal (the same number), in decimal
( + Efllt) and also in octal and binary. The decimal value E flit is what
we need.
Return to BASIC (using the X command). The computer will say READY;
you may now call your program with a SYS command.
The computer has told us that address SDBOD is Efllt in decimal. If
we had forgotten to ask before leaving the ML M, we could now ask BASIC
with PRINTDECC'QBOO"); we'd get the same value of 5 fl 1 fc printed.
Now we type BANK15:SYS2fllt. When we press RETURN, the letter
H will be printed.
Don't forget the reason that we are using BANK 15— it's to make sure
that we reach both our program in R AM (below hex < □ □ D) and the Kernal
ROM (hex 4D0D and above) at the same time to avoid extra "switching"
work. Now we may type NEW and enter a BASIC program:
262 MACHINE LANGUAGE FOR COMMODORE MACHINES
!□□ BANK 15
IID FOR J = l TO ID
lED SYS Efllt,
13D NEXT J
If you prefer, you're allowed to say SYS DEC( "BDD" ) in line lED.
BASIC commands know only decimal numbers, so we must translate from
hex one way or another.
Loops project:
a OBUU LDX #□
fi DBDS LDfi $BDE,X
A DBDS JSR $FFDE
ft DBDa INX
ft DBOq CPX #t
ft DBDB BNE $BD2
ft DBDD RTS
After entry, the program looks like this:
ft DBDO Aa □□ LDX#$DQ
ft OBDS BD DE DB LDA$DBDE,X
A DBDS 5D D5 FF JSR $FFD5
ADBDflEfl INX
AOBOqEODE, CPX#$Dt
A DBDB DD F5 BNE $0605
A OBDD bD RTS
We guessed (or planned) that the address $DBDE would be available for
our message HELLO. Now we must store these characters in memory.
Command M BDE BIB, and type over the display to show
>DOBDE A& AS AC AC AT OD xx xx
Return to BASIC (with X) and try BANK 15 : SYS EfllL. The computer
should say HELLO.
Once again, you may set up a BASIC loop program:
lOD BANK 15
IID FOR J = l TO 3
lED SYS Efllt
13DNEXTJ
To preserve the program within DATA statements, type:
FOR J = 2fllL TO 5a35:PRINT PEEK(J) ; :NEXT J
Study the above line. You will see that it asks BASIC to go through the
part of memory containing your machine language program, and display
the contents (in decimal notation, of course). You'll see a result that looks
something like this:
ILE □ laq lA 11 32 210 ess 532 t
EDfl 5^5 7E bq 7t 7t 7q 13
APPENDIX E — EXERCISES FOR THE CI 28
263
You may arrange these within data statements:
50 DATA ltS,D,lfiq,l<,ll/3E,210,E55,235,5E4,fc
tD DATA EDa,545,qt,7E,bR,7t,7t.,7q,13
flD FOR J = 5fllt TO afl35:READ XrPOKE J,X:NEXT J
. . . and our program continues as before with:
IDD BANK 15
IID FOR J = l TO 3
150 SYS salt
13D NEXT J
From Chapter 3:
Input exercise:
A ODBOD JSR $FFE1
A 00BD3 BEQ $B15
A QDBD5 JSR $FFE<
A □□BDfi GMP #30
A OQBQA BCC $QBOO
A DDBOC CMP #3A
A □□BDE BCS $BDO
A DDBIQ JSR $FFD2
A DDBIS AND #$DF
A DDBIS RTS
The fonvard branch to $ □ B 1 5 was a guess, but it turns out to be correct.
The final assembly looks like this:
A
□ □BDO
ED
El
FF
JSR
$FFE1
A
□ □BD3
FO
ID
BEQ
$DB15
A
□ □BDE
EO
E^
FF
JSR
$FFE<
A
aQBDfl
cq
3D
CMP
#$3D
A
QOBOA
qn
TA
BCC
$DBDD
A
DDBGC
cq
3A
CMP
#$3A
A
ODBDE
BO
FD
BCS
$DBDD
A
□ DBIO
ED
DE
FF
JSR
$FFDE
A
D0B13
Eq
DF
AND
#$DF
A
□ □B15
tD
RTS
Call the subroutine for testing with BANK 15:SYS 2816.
From Chapter 4:
Addition program:
Be sure that the above code from the previous chapter has been entered
before continuing with the main program:
A DDBIL JSR $BDD
264
MACHINE LANGUAGE FOR COMMODORE MACHINES
A
□ DBiq
STA
$Bta
A
□ □BIC
LDA
#$5B
A
□ □BIE
JSR
$FFD5
A
□ □BEl
JSR
SBDD
A
TAX
A
□ □B55
LDA
#$3D
A
□ □B27
JSR
$FFDE
A
□ DBEA
TXA
A
QDBEB
CLC
A
□ □BEC
ADC
$Bt,a
A
□ □B5F
ORA
#$3D
A
DDB31
JSR
$FFDE
A
□ 0B3^
LDA
#$PD
A
□ 0B3t
JSR
$FFDE
A
□ 0B3q
RTS
As a matter of style, you might prefer to type addresses as four digits of
hex ($DBDD rather than SBDD) to remind yourself that you're dealing
with sixteen bits. The dollar sign isn't needed, but I suggest you keep it.
When you graduate to a full symbolic assembler, you'll be required to use
the dollar sign; you might as well keep in practice.
The assembled screen code looks like this:
A
□ □Bit
EO
DD
□ B
JSR
$DB^^
A
ODBiq
flD
□ B
STA
$QBba
A
□ □BIG
Aq
EB
LDA
#$EB
A
□ □BIE
£□
DE
FF
JSR
$FFDE
A
□ □BEl
BQ
□ □
□ B
JSR
$DB^^
A
AA
TAX
A
□ □BS5
AS
3D
LDA
#$3D
A
□ □BE?
ED
DE
FF
JSR
$FFDE
A
□ □BEA
flA
TXA
A
□ □BEB
Ifl
CLC
A
□ □BEC
LD
hU
□ B
ADC
$^Bt^
A
□ □BEF
□q
3D
ORA
#$3^
A
□ □B31
ED
DE
FF
JSR
$FFDE
A
UUBIA
Aq
□ D
LDA
#$□0
A
□ □B3b
ED
DE
FF
JSR
$FFDE
A
□ □B3q
tD
RTS
Remember we don't want to SYS to address $BD^ (S flit)— that's the
subroutine. Instead, command BANK 15:SYS 2838 which takes us to the
main routine at $ □Bit.
APPENDIX E — EXERCISES FOR THE C128
265
From Chapter 5:
Project: Screen Manipulation
It's not possible to do a simple POKE to the screen when you are in the
Commodore 1 28's 80-column mode, so this example must be for the 40-
column configuration only. The first instruction uses a decimal value of 40
rather than hex 28.
ft DDBOO
LDft
* + A0
ft DDBOe
STft
$B&D
The 40-column screen is usually at $04 DO.
ft DDBDS
LDX
*$UA
ft DDBD?
STX
$BC
ft DDBaq
LDft
#$□□
A DDBOB
STft
$BB
ft DDBOD
LDX
#□
Here's where we start on a new line
ft ODBDF
LDY
#$UA
And this is where we handle the next column.
A □□Bll
LDA
($BB) ,Y
ft DOBIB
CMP
#$E0
ft ODBIB
BEQ
$B1S
ft DDBl?
EOR
#$flD
ft DOBiq
STft
($BB) ,Y
A ODBIB
INY
A DDBIC
CPY
# + lfl
ft ODBIE
BCC
$B11
ft ODBEO
CLC
ft DDBEl
LDft
$BB
ft DOBEB
ftDC
$B&0
A DDBEb
STft
$BB
A DDBEfi
LDft
$BC
A DDBEA
ftDC
#$□□
ft DOBEC
STft
$BC
ft ODBEE
INX
ft DOBEF
CPX
# + lA
ft DOBai
BNE
$BDF
A DOBBB
RTS
The assembled code
will look like the following. There's not enough room
on the screen to see it all at once,
ft DDBDa ftq Efi LDft #$Efl
ft DQBDE flD flD DB STft SDBflD
ft □□B05 ftE 04 LDX #$04
266
MACHINE LANGUAGE FOR COMMODORE MACHINES
H
U U D U f
AL
U D
RP
DC
O X A
i;rp
B
n
U U D U n
nn
U u
7r ^ u u
a
U U O UD
RR
DD
O X n
■CRR
4>DD
a
n
nnRnn
U U D u u
a p
nn
U U
T n Y
J-i JJ A
a6t<t;nn
#^iP u u
n
n
nnRiTP
u UD u r
a n
T nv
a
n
nriRi.i.
R1.
D Jj
RR
DD
i-i JJ n
^ "RRR ^ V
\ 4>DD ^ / 1
B
xi
U UD Jj J
PP
C U
PMP
W9CU
n
n
U Imi *J M J
X LJ
□ 3
LJ L_
BEO
4* LJ U JU 1
ft
□ OBI?
LJ LJ XJ JJ 1
fin
U LJ
EOR
TT LJ LJ
a
BB
STA
ij X n
( $BB ^ . Y
a
□ □BIB
LJ U U ^ JJ
LJ
INY
X Li X
a
U LJ U JJ ^
CO
LJ
CPY
#$1P
TT JJ I—
ft
□ □BIE
LJ LJ U JJ U
1 LJ
X JJ
BCC
u v_« v«
*|f U U ^ Jl
a
□ □B3^
U LJ U ^ LJ
JJ LJ
CLC
v« xj %^
LJ LJ JJ JU
n?
n J
BB
JJ JJ
i./ fl
$BB
4J AJ XJ
a
n
LJ LJ U L. ^
□ ly
LJ LJ
□ B ADC
LJ JJ XI jy ^
SDBfin
*if LJ JU LJ LJ
n
n
U U D C D
U 3
iJ xj
tj X A
A
ooBaa
AS
BC
LDA
$BC
A
□ □B5A
□ □
ADC
#$□□
A
□□sac
fiE
BC
STA
$BC
A
□ DB5E
Efl
INX
A
□ □B2F
ED
□E
CPX
#$DE
A
□ □B31
DD
DC
BNE
$DBDF
A
□ □B33
to
RTS
Now for the BASIC program to demonstrate how it all works:
IQQ BANK 15
IID FOE J = l to ID
lEO SYS Efilt
130 FOR K = l to 5DD
KO NEXT K/ J
From Chapter 6:
We can do the exercise, but there are new rules that we must iearn.
The Commodore 128 has more than one bank of memory, and different
things are found In different banks. The role of pointers in keeping various
types of data separate is not the same as before. An earlier Commodore
machine (the B-128 or 700 series) had this same kind of muiti-bank ar-
chitecture, and some of the following comments will also apply to that
machine.
APPENDIX E — EXERCISES FOR THE C128
267
Siting Beliind BASIC
About the pointers: Our BASIC program is in bank 0, but the variables,
arrays and strings are in bank 1 . This means that the start-of-BASIC pointer
works with a different memory bank than the others. When we place a
machine language program directly behind a BASIC program we are in
no danger of bumping into variables. There is a pointer, saying where the
empty space starts in bank — the pointer is at hex 1 E 1 □ , decimal AhEA —
but it mustn't be confused with start-of-varlables.
On the Commodore 128, a BASIC program usually is stored at address
$1CD1. The address may change if graphics functions are used. That's
quite a high address compared to most other Commodore machines. You
may establish where a program ends by checking addresses $ 1 E 1 □ and
$1E11. If you wish to write a program that will be located in bank but
above your BASIC program, the pointer will tell you the area that's safe.
After you have placed your program in the appropriate part of memory,
you may move the pointer up. From that point on, BASIC and machine
language will load and save together as a unit.
We're going to use this parked-behind-BASIC location in the exercise.
There's one more caution, however. If you want the ease of bank 15
operation, with simple access to your program In RAM and the Kernal In
ROM, you must make sure that your programs — BASIC and machine
language together — don't go above address $ADQQ. Beyond that point,
you'll have to carefully call banking subroutines — principally the one at
$ □ E CD— to make sure that everything works together. For our tiny sample
program, that's no problem.
Crossing The Banics
Here's a new problem. Our program— located in bank 0— is going to look
at and change BASIC variables as they lie in memory. How can a program
in bank look at and change data in bank 1 ? We must learn about the
subroutines that allow us to do this.
To LOAD from any memory bank, we must call subroutine INDFET (indirect
fetch), located at address $TT7A. Set things up as if you are about to
do a LDA (..),Y command. That calls for first setting up an indirect address
somewhere in page zero. Tell the subroutine where the indirect address
is located by loading its address into the A register. Then load the bank
number into register X, load Y with an appropriate value for indirect use,
and call JSR $FF7<.The data from the appropriate bank will be re-
turned in the A register.
268 MACHINE LANGUAGE FOR COMMODORE MACHINES
To STORE in any memory bank, we must call subroutine INDSTA (indirect
stash), located at address $FF77. Set things up as if you are about to
do a STA (..),Y command. That calls for first setting up an indirect address
somewhere in page zero. Tell the subroutine where the indirect address
is located by storing it into address SDEBR. Then load the bank number
into register X, load A with the data to be stored, load Y with an appropriate
value for indirect use, and call JSR $FF77. The data will be stored in
the appropriate bank.
Project
Type NEW and enter the BASIC program as follows:
IDD V^ = D:BaNK 15
110 FOR J = l TO 5
lED INPUT "VaLUE" ;
13D SYS + + + +
lAO PRINT "TIMES TEN = ";V%
15D NEXT J
Assuming that our BASIC program will occupy less than 127 bytes and
that BASIC starts at IICDI (decimal 7169) we can start our machine
language program at around 7169 + 127, or 7296 (hexadecimal ICflD).
On that basis, we may change line 13D to SYS 7EREj. Do nof try to
run the program yet. It would be a good idea to call the monitor briefly
and display the contents of memory address 151D-1E11 to confirm
that we are in the right range.
Switch into the machine language monitor. Assemble the following code,
(the indirect address)
(bank 1)
but don't type
the comments
A
DlCflD
LDY
#$DE
A
DlCflE
SEI
A
DlCflB
LDA
#$5F
A
□ ICflS
LDX
#$□1
A
□ lCfl7
JSR
$FF7A
A
OlCflA
STA
$DBDO
A
OlCflD
STA
$□302
A
□icqo
LDY
#$□3
A
□icq?
LDA
#$2F
A
□ ICS-^
LDX
#$□1
A
□icqt
JSR
$FF7<
A
□icqq
CLI
A
DicqA
STA
SQEQl
A
DicqD
STA
$aBa3
A
□ ICAD
ASL
SDBDl
A
01CA3
ROL
SOBOa
APPENDIX E — EXERCISES FOR THE C128
269
A
k
h
h
A
A
A
A
A
A
A
A
A
A
A
A
A
A
A
A
A
A
A
□ ICAb
OICAR
OICAC
QICAD
□ ICBD
□ 1CB3
□ ICBt
□ ICBR
□ ICBC
□ ICBF
□icca
01CC5
OlCCb
DlCCfl
DICCA
□ ICCD
□ ICCF
01CD2
□ 1CD5
□ 1CD7
□ ICDA
□ ICDC
□ ICDF
DICED
ASL
ROL
CLC
LDA
ADC
STA
LDA
ADC
STA
ASL
ROL
SEI
LDY
LDA
STA
LDX
LDA
JSR
LDY
LDA
LDX
JSR
CLI
RTS
$DBD1
$DBDD
$DBai
$DBD3
SDBQl
$DBDD
SDBDE
$DBDD
$DB01
$DBDD
#$Q5
#$EF
$DEBR
#$□1
$OBDD
$FF77
#$□3
$DB01
#$01
$FF77
(the indirect address)
(bank 1)
The assembled code will look like this:
A
DlCfiD
AD
DE
LDY
#$DE
A
□ ICfiS
7fl
SEI
A
Dica3
Aq
EF
LDA
#$EF
A
□ ICflB
A5
Dl
LDX
#$D1
A
□ lCfl7
ED
7A
FF
JSR
$T?7A
A
□ ICflA
flD
OD
DB
STA
$DBDD
A
□ ICflD
BD
DE
DB
STA
$DBDE
A
DIC^D
AD
D3
LDY
#$03
A
□icqs
AH
EF
LDA
#$EF
A
□icq<
Ad
Dl
LDX
#$01
A
DlCRt
2D
7A
FF
JSR
$FF7/;
A
Dicqq
5fl
CLI
A
DicqA
flD
Dl
DB
STA
$0B01
A
DICHD
fiD
D3
DB
STA
$0B03
A
□ ICAD
DE
Dl
DB
ASL
$0601
A
D1CA3
EE
DD
DB
ROL
$0B00
A
DlCAt
DE
Dl
DB
ASL
$0B01
A
DICAR
EE
DD
DB
ROL
$DBOD
270 MACHINE LANGUAGE FOR COMMODORE MACHINES
A
OICAC
Ifl
CLC
A
□ ICAD
AD
Dl
DB
LDA
$DBDl
A
□ ICBD
tD
D3
DB
ADC
$nBD3
A
□ 1CB3
flD
Dl
DB
STA
$DBD1
A
□ ICBt
AD
DD
DB
LDA
$DBDD
A
□ 1CB9
bD
□ E
DB
ADC
$DBDE
A
□ ICBC
flD
DD
DB
STA
$PBDD
A
OICBF
□E
Dl
DB
ASL
$DBD1
A
01CC2
5E
DD
DB
ROL
$DBDD
A
□ 1CC5
7a
SEI
A
□ ICCt
AD
DE
LDY
#$DE
A
Dicca
A=1
SF
LDA
#$SF
A
□ ICGA
fiD
B'=\
DE
STA
$DEB'^
A
□ ICCD
AS
Dl
LDX
#$D1
OICCF
AD
DD
DB
LDA
SDBOD
1— 1 iJ LJ LJ
A
01CD2
ED
77
FF
JSR
$FF77
A
□ 1CD5
AD
D3
LDY
#$D3
A
□ 1CD7
AD
Dl
DB
LDA
$0BD1
A
□ ICDA
A5
Dl
LDX
#$D1
A
OICDC
2D
77
FF
JSR
$FF77
A
□ ICDF
5fl
CLI
A
DICED
to
RTS
We must change the End-of-BASIC pointer to a location above the ma-
chine language program. That would be $1CE1, and so we display the
BOB pointer with M lElD 1 Ell and change the pointer to
>1S1D El IC ............
Check . . . disassemble . . . and then back to BASIC. List, and you'll see
your BASIC program again. There's no sign of the machine language
program, of course, but SAVE will now save everything together. You may
now RUN.
From Chapter 7:
Interrupt Exercise
The interrupt:
A DDBDD LDA
A DDBDE STA
A DDBD5 JMP
The enable:
A DDBDfl LDA
A DDBDB STA
A DDBDE LDA
A DDBll STA
$qi
$D4DD
($DB5D)
$D31A
$DB5D
$D315
$DB51
APPENDIX E — EXERCISES FOR THE C128
271
A
□ □BI^
SEI
A
□ 0B15
LDfl
, #$□□
k
□ DB17
STA
, $^31^
A
DDBliA
LDA
, #$^B
A
DDBIC
STA
, $D31^
A
□ QBIF
CLI
A
DDB5D
RTS
The disable:
A
ODBai
SEI
A
□ □B5a
LDA
$UBSO
A
□ □B25
STA
$□314
A
DDBSa
LDA
$DB51
A
□ 0B2B
STA
$0315
A
OOBEE
CLI
A
□ □B2F
RTS
The completed program should look like this:
A
□ □BDD
AS
LDA
$S1
A
Q0BD2
flD
□ □
DA
STA
$0400
A
□ □BQ5
tc
SD
QB
JMP
($DB5D)
A
□ □BDfl
AD
03
LDA
$0314
A
□ QBOB
flD
50
□ B
STA
$0B5D
A
ODBDE
AD
15
□ 3
LDA
$□315
A
□ □Bll
flD
51
□ B
STA
$0B51
A
□ QB14
7fl
SEI
A
0QB15
AS
□ □
LDA
#$00
A
DDB17
flD
03
STA
$0314
A
ODBIA
Aq
OB
LDA
#$DB
A
□ OBIC
flD
15
□ 3
STA
$□315
A
ODBIF
5fl
CLI
A
□ □BSD
i=n
RTS
A
□ □BEl
7fl
SEI
A
□ aB22
AD
50
□ B
LDA
$0B5^
A
□ □B25
flD
lA
□ 3
STA
$□314
A
□ □BEfl
AD
51
□ B
LDA
$DB51
A
□ □BEB
flD
15
□ 3
STA
$□315
A
□ □BEE
5fl
CLI
A
□ □BEF
RTS
Enable the new interrupt procedure by a SYS to $^B^fl, above (SYS
2824). Return to the "standard" interrupt with a call to $^BS1 (SYS 2849).
Project: Adding a Command
CHRGET is now at address $03 flD. TXTPTR is still in zero page, how-
ever, at $ 3D. We use coding quite similar to that for the Commodore 64.
272 MACHINE LANGUAGE FOR COMMODORE MACHINES
Here's the "intercept":
□ OBDO
L-l LJ LJ LJ LJ
LDY
#1
ft
OOBDE
LDA
( S3D ) . Y
A
□ □BD^
CMP
#SEt
LJ LJ ±J LJ O
U J-J \^
SBDB
JL/ LJ U
ft
I—I LJ U LJ LJ
JMP
V LJ XJ — J LJ J
ft
□ □BOB
LJ LJ U LJ U
JSR
KJ t>J L\
$0360
k|/ LJ J LJ IJ
A
CI
U LJ LJ LJ JJJ
LDY
#0
TT LJ
ft
□ □BID
LJ LJ LJ LJ
LDA
TT 4* ^ n
A
□DBia
JSR
$FFDE
a
noBis
INY
A
□ □Bib
CPY
# + !□
A
OOBlfl
BCC
$B1E
A
□ OBIA
LDA
#$0D
A
□ OBIC
JSR
$FFDE
A
ODBIF
JMP
$BDfi
ere's the link to turn it on:
A
LDA
$D30fl
A
□ □B55
STA
$B5D
A
□ □BEfl
LDA
$D3Qq
A
□ □BEE
STA
$B51
A
DOBEE
LDA
#$DD
A
00B3D
STA
$03Dfl
A
□ □B33
LDA
#$DB
A
0DB35
STA
$D30q
A
□ □B3fl
RTS
The assembled code will look like this:
a
□ □BQD
AO
01
LDY
#$□1
A
□ OBOE
Bl
3D
LDA
{$3D) ,Y
A
□ □BD4
cq
Et
CMP
#$Efc
A
□ □BDt
FD
□ 3
BEQ
$^B^B
A
□ □BOfi
tc
5^
□ B
JMP
($^B5^)
A
□ □BOB
E^
□ 3
JSR
$^3aD
A
QDBDE
A^
□ □
LDY
#$□□
A
□ OBIO
Aq
EA
LDA
#$EA
A
□ □BIE
E^
DE
FF
JSR
$FFDE
A
□ □B15
Cfl
INY
A
□ □Bit
€□
□ A
CPY
#$^A
A
□ □Blfi
q^
Ffl
BCC
$^B1E
A
□ □BIA
aq
□ D
LDA
#$DD
A
□ □BIC
£□
DE
FF
JSR
$FFDE
A
□ □BIF
<c
□a
□ B
JMP
$^B^a
A
□ □BEE
AD
□a
□ 3
LDA
$^3Qa
APPENDIX E — EXERCISES FOR THE C128
273
a DDBES
ft ODBEfl
A DDBEB
A DDBEE
ft ODBaO
A DDBBB
A DDBBB
A DDBBfl
flD 50
AD oq
flD 51
AR □□
flD Dfl
AS OB
flD
to
□ B STA
□ 3 LDA
□ B STA
LDA
03 STA
LDA
03 STA
RTS
SOBSO
$03Dq
$0B51
#$00
$030a
#$DB
$030^
When you have completed and checked the code return to BASIC. Type
NEW and write the following program:
100 PRINT 3+^:&:PRINT 5+t
110 &
150 PRINT "THAT'S ALL"
Type RUN and you'll get a SYNTAX ERROR in line 100. Now implement
the "ampersand" feature with BANK 15:SYS 2850. Type RUN again. The
ampersand command obediently prints ten asterisks each time it is in-
voked. A point of interest: in the two examples in this chapter, bank will
work. Can you see why?
From Chapter 8:
Output Example
To put the message HI on the printer:
100 OPEN I, A
110 BANK 15:SYS Efllfc
lED CLOSE 1
The machine language:
A OOBOD LDX #$01
A D0B02 JSR $FFCS
A DDB05 LDA #$A&
A 00BD7 JSR $FFDE
A OOBOA LDA #$<q
A OOBOC JSR $FFDE
A DOBOF LDA #$0D
A OOBll JSR $FFDE
A 00B14 JSR $FFCC
A 00B17 RTS
The assembled code:
A OOBOD AE 01 LDX #$01
A OOBOE ED CH FF JSR $FFCH
A DDBD5 AS A6 LDA #$4fl
A DDB07 ED DE FF JSR $FFDE
274
MACHINE LANGUAGE FOR COMMODORE MACHINES
A □DBDA ftR LDft #$A^
a DDBDC EQ D5 FF JSR $FFDE
a odBDF aq dd LDa #$dd
a □□Bll 5D D2 FF JSR $FFD2
a ODBK EO CC FF JSR $FFCC
a DDBl? to RTS
Input Example
Create the file as described in Cliapter 8. The BASIC program is also
similar except for the SYS command:
!□□ OPEN 1, a, 3, "DEMO"
IID BANK 15:SYS afllt
12D CLOSE 1
The machine language program:
a DDBDn LDX #$□!
a DDBDE JSR $FFCt
a DDBDS JSR $FFE4
a □DBDfl JSR $FFD5
a noBDB LDa $qD
a DDBGD BEQ $DBQ5
a DDBaF JSR $FFCC
a DOBIE RTS
The assembled code:
a
□ □BDD
RE
Dl
LDX
#$D1
a
□ □BDE
ED
Cb
FF
JSR
$FFCt
a
□ □BD5
ED
E4
FF
JSR
$FFE^
a
□ DBOfl
ED
DE
FF
JSR
$FFD5
a
□ □BOB
as
qD
LDa
$qD
a
□ □BOD
FD
Ffc
BEQ
$DBD5
a
□ □BDF
ED
CC
FF
JSR
$FFCC
a
□ □B12
hU
RTS
A File Transfer Program
Here comes BASIC:
!□□ PRINT "FILE TRANSFER"
!!□ INPUT "INPUT FROM (DISK, TAPE)" ; A$
lED IF LEFT$(A$,1) = "T" THEN OPEN 1:G0T0 ItD
13D IF LEFT$(A$,1)<> "D" GOTO IID
l^D INPUT "DISK FILE NAME" ;N$
15D OPEN l,fl,3,N$
ItD INPUT "TO (DISK, TAPE, SCREEN) ";B$
17D IF LEFT$(B$,1) = "S" THEN OPEN S,3:G0T0 E^D
IflD IF LEFT$(B$,1) = "D" GOTO EID
iqD IF LEFT$(B$,1)<>"T" GOTO ItD
APPENDIX E — EXERCISES FOR THE C128
275
EDO IF LEFT$(A$,1) = "T" GOTO ItD
EIQ INPUT "OUTPUT FILE NAME" ; F$
55D IF LEFT$(B$,1) = "D" THEN OPEN
530 IF LEFTS (B$, 1) = "T" THEN OPEN E,l,lrF$
2An BANK 15:SYS 7tflD
ESn CLOSE E: CLOSE 1
The above BASIC program should not take up more than 51 1 bytes; on
a standard Commodore 128, that means that we'll have clear space for
our machine language program starting at $1ED0 (decimal 7680). We'll
move the end-of-BASIC pointer along, of course (NOT the start-of-vari-
ables), so that our machine language program will save together with
BASIC.
A
□ lEDD
LDX
#$D1
A
□ lEDE
JSR
$FFCt
A
□ lEDS
JSR
$FFE<
A
□ lEDfl
LDX
$10
A
□ lEOA
PHP
A
□ lEDB
PHA
A
□ lEOC
JSR
$FFCC
A
QIEQF
LDX
#$DE
A
□ lEll
JSR
$FFCq
A
□ 1E14
PLA
A
01E15
JSR
$FFDE
A
OlElfl
JSR
$FFCC
A
OIEIB
PLP
A
□ lElC
BEQ
$1E00
A
□ lElE
RTS
le assembled code is:
A
□ lEDD
AE
Dl
LDX
#$D1
A
□ lEDE
ED
Ct
FF
JSR
$FFCt
A
□ 1ED5
ED
EA
FF
JSR
$FFE4
A
OlEDfl
At
^Q
LDX
$SD
A
□ lEDA
Dfl
PHP
A
□ lEDB
^fl
PHA
A
□ lEOC
ED
CC
FF
JSR
$FFCC
A
DIEOF
AE
DE
LDX
#$DE
A
DlEll
EO
cq
FF
JSR
$FFCq
A
OIEIA
tfl
PLA
A
□ 1E15
ED
DE
FF
JSR
$FFDE
A
□lEia
ED
CC
FF
JSR
$FFCC
A
□ lElB
Efl
PLP
A
OIEIC
FD
EE
BEQ
$1EDD
276 MACHINE LANGUAGE FOR COMMODORE MACHINES
A DIEIE to BTS
Be sure to move the Start-of-Variables pointer ($D2ia/$DEll) so that
it points at address $1E1F.
F
Floating
Point
Representation
277
278 MACHINE LANGUAGE FOR COMMODORE MACHINES
Packed: 5 bytes (as found in variable or array)
Zero
Flag/
Exponent
Mantissa (value)
4 bytes
High bit represents sign of mantissa
Unpacl<ed: 6 bytes (as found in floating accumulator)
ZF/
Exponent
1
Mantissa-
—4 Bytes
Sign
(High Or-
der
Bit only)
• If exponent = 0, the whole number is zero
• if exponent > $80, the decimal point is to be set as many places to the
right as the exponent exceeds $80.
• Example: Exponent: $83 mantissa: 11000000 . . . binary set the point
three positions over: 1 10.000 ... to give a value of 6.
• If exponent < = $80, the number is a fraction less than 1 .
Exercise: Represent +27 in Floating Point
27 decimal = 1 101 1 binary; mantissa = 1 101 1000 ... the point is to be
positioned 5 places in (1 101 1 .000 . . .) so we get:
Exponent: $85 mantissa: 11011 000 . . . binary or D8 QO 00 00 hexadecimal
To pack, we replace the first bit of the mantissa with a sign bit (0 for
positive) and arrive at:
fl5 5fl □□ OD □□
G
Uncrashing
It's best to write a program that doesn't fail (or "crash"). Not all of us
succeed in doing this.
If a program gives trouble, it should be tested using breakpoint techniques.
The BRK (break) instruction is inserted at several strategic points within
the program. The program stops (or "breaks") at these points, and the
programmer has an opportunity to confirm correct behavior of the program
at selected points. Using this technique, a fault can be pinned down quite
closely.
Occasionally, usually because of bad planning, a program crashes and
the cause of the crash cannot be identified. Worse still, a lengthy program
crashes and the user has forgotten to save a copy of it; the user is then
faced with the task of putting it in all over again.
In such cases, uncrashing techniques are sometimes available to bring
the computer back from limbo. They are never entirely satisfactory, and
should be thought of as a last resort.
The technique differs from computer to computer.
279
280
MACHINE LANGUAGE FOR COMMODORE MACHINES
PET/CBM
Original ROM PETs cannot be uncrashed.
Subsequent models can be uncrashed, though hardware additions are
necessary. The reader should find someone with computer hardware
knowledge to assist in fitting the switches to the computer.
A toggle switch is needed, to be connected to the "diagnostic sense" line
of the parallel user port; that's pin 5 of the PUP. The other side of the
toggle switch should connect to ground (pin IE).
Additionally, a momentary pushbutton is required. This must connect the
reset line of the computer to ground. Technically speaking, it's better to
trigger the input of the computer's power-on reset chip (a 5 55 one-shot),
using a resistor to guard against accidentally grounding a live circuit.
To uncrash, set the toggle switch to "on" and press the pushbutton; the
machine will come back to life in the machine language monitor. Set the
toggle switch off. There's more work to do.
The computer is still in an unstable state. To correct this, either of two
actions may be taken. You may return to BASIC with . X and immediately
give the command CLE; Alternatively, you may type . ; followed by the
RETURN key.
Whatever investigation or other action is needed should be performed
quickly and the computer reset to its normal state.
VIC/Commodore 64
You might try holding down the RUN/STOP key and tapping the
RESTORE key to see if that will bring the machine to its senses. 0th-
enwise, you must do a more serious reset.
You must depend on the fact that the computer does a nondestructive
memory test during reset. There are various commercially available in-
terfaces for the cartridge port— usually "mother boards" that are fitted with
reset switches.
When the reset switch is pressed, the computer starts from the beginning;
but memory is not disturbed. If you have logged the entry location of the
machine language monitor, you can bring it back with the appropriate SYS
command.
APPENDIX G — COMMODORE PLUS/4
281
Commodore PLUS/4
There's a reset button next to the power switch. Before you press it, hold
down the RUN/STOP and CTRL l^eys. Now press the reset button and
you'll find yourself in the machine language monitor.
H
Supermon
Instructions
Commodore 128 users should turn to page 290, which also Includes a
summary of instructions to SUPERMON+ for C64 users who also want a
better monitor.
Program Supermon is not a monitor; it is a monitor generator that will
make a machine language monitor for you. There's a reason for this.
Supermon finds a likely spot in memory and then plunks the MLM there
so as to fit it into the most suitable place.
Load Supermon and say RUN. It will write an MLM for you, and call it up.
Now, exit back to BASIC and command NEW. You do not want the MLM
builder any more (it's done the job) and you do not want the danger of
building two — or more — MLM's. Get rid of the generator program. Any
time you need to use the MLM, give SYS^ or SYSfl, as appropriate.
Supermon contains the following "essential" commands:
R — to display (and change) registers
M — to display (and change) memory
S — to save memory to disk or tape
L — to load from disk or tape
G — to go to an ML program
X— to exit to BASIC
Supermon also contains the following extra commands:
A — to assemble
D — to disassemble
283
284
MACHINE LANGUAGE FOR COMMODORE MACHINES
Most versions of Supermon (not the "do-it-yourself" below) contain the
following commands. Though not used by this book, they are useful:
F — fills memory with fixed contents:
F l&nO IflFF □□
H — hunts for a memory pattern:
H DfiDD IfiDD 2D D2 FF
T — transfers a block of memory to a new location:
T DfiDO DBFF flDDD
A few versions of Supermon contain the command .1 which causes ma-
chine language single stepping.
A Do-lt-Yourself Supermon
If you do not have access to Supermon from friends, dealers, clubs, or
disk, you may find the following program useful for the Commodore 64
only.
Enter this program (it will take you hours). Be sure that lines 3QD and
above are correct; the lower numbered DATA lines will be checked for
accuracy by the program.
When you say EON, the program will run in two phases. Part 1 takes over
two minutes to run: it will check all DATA statements for missing lines
and errors and report any problems to you. Part 2 will run only if part 1
shows no errors: it will cause the program to "collapse" into itself, resulting
in Supermon. The moment the program has completed running, save
Supermon to disk or tape.
The Supermon generated by this program is a "junior" version (to save
your fingers) but it contains all commands needed for this book.
1 DATA Bb, fl, 153, 34, 1^7, ia,Eq,Eq, - 3D
2 DATA 2q,Bq,fl3,fi5,flD,tq,aE,32,54,5E,-lt
3 DATA 45,77,?q,7fi,D,4q,fl,llD,D,153,-3q
A DATA 34,17,32,3E,3E,3E,3E,3E,3E,3E,-5D
5 DATA 3E,3E,3E,3E,3E,3E,3E,D,75,fl, -3
t DATA lED,n,153,34,17,3E,4fc,4fc,74,73,-4fl
7 DATA 77,3E,bb,fl5,fl<,fl4,bq,fiE,7D,73,-5b
fl DATA tq,7fc,tfi,D,lDE,fl,13D,D,15fl,4D, -4
q DATA iq4,<D,5E,51,41,17D,5D,53,54,17E, -53
ID DATA iq<,<D,5E,5E,41,17D,4q,5D,55,41, -E5
11 DATA D,D,D,17D,17D,17D,17D,17D,17D,17D, -fc^
IE DATA 17D,17D,170,17D,17D,17D,17D,17D,17D,17D, -Eq
APPENDIX H — A DO-IT-YOURSELF SUPERMON
285
13 DaTR 17D, 170, 17D, 170,170, 170, 17D, Its, <5, 133, -bl
lA DATR 3^, lb5,4t, 133, 35, Its, 55, 133, 3b, Its, - IE
15 DRTA 5b,133,37,lbD,D,lt,5,3<,2Dfl,5,lRa, -55
lb DRTa 3 5,iqa,3^,177,3<,B0fl,b0,lb5,34,EDfl, -34
17 DATA E,iqa, 35, 1^3,3-^,177, 34,24 0,33,133, -52
Ifl DfiTR 3fl,lb5,34,EDfl,5,iqfl,3 5,iqfl,34,17 7, -bD
iq DATA 34,E4,lQl,3b,17D,lb5,3 6,iai,37 ,7 2, -5b
ED DftTft lb5, 55, EOfl,E,iqfl, 5b, IRfl, 55,104, 145,-1
El DRTft 55,13a,7E,lb5,55,EDfi,E,lSa,5b,iqa, -1
EE DftTft 55, 104,145, 55, E4, 144, iaE,E01,7q,EDa, - 4a
E3 DftTft E37,lb5,55,133,51,lb5,5b,133,5E,lDa, -17
E4 DftTft 55, □,7q, 7 q,7q,7q, 173, E3D,E55,D, - EE
E5 DftTft 14 1, EE, 3, 173, E31,E55, 0,141,23, 3, -b4
Eb DftTft lbq,lEa,3E,144,E55,D,D,Elb,lD4,141,-3D
E7 DftTft bE,E,104,l41,bl,E,104,141,bO,E, -41
Ea DftTft 104, 141, Sq, 2, 104, 17 0, 104, Iba, 5b, 13a, -17
Eq DftTft E33,E,141,5a,E,152,E33,0,0,141, - IE
30 DftTft 57,E,iab,14E,b3,2,32,147,E53,0, -57
31 DftTft lbE,bb,lbq,4E,3E,ED5,251,0,lbq,aE, -bE
3E DftTft E0a,4E,E3D,iq3,E0a,b,E30,iq4,E0a,2, -52
33 DftTft E3D,3a,qb,3E,ED7,S55,E01,13,2Dfl,24a, -24
34 DftTft 104,104,lbq,0,D,133,3a,lb2,13,lbq, -11
35 DftTft 4 b, 32, 205, 251, 0,32, 220, 24q, 0,201, -32
3b DftTft 4b,24 0,24q,201,32,24D,245,lb2,14,221, -23
37 DftTft iq5,255,D,20a,12,13a,10,17 0,iaq,207, -3b
3a DftTft 255,0,72,iaq,20b,255,0,7 2,qb,2D2, -E
3q DATA lb,E3b,7b,a0,E5E,D,lb5,iq3,141,5a, - Eq
40 DATA E,lb5,iq4,141,57,E,qb,lbq,a,133, -44
41 DATA Eq,lb0,0,0,3E,143,E53,0,177,iq3, -31
42 DATA 32,iq0,251,0,32,2Dq,24q,D,iqa,2q, -bl
43 DATA 20a,241,qb,32,254,251,0,144,ll,lb2, -53
44 DATA 0,0,12q,iq3,iq3,iq3,24 0,3,7b,aD, -5a
45 DftTft E5E,o,3E,Eoq,E4q,o,iqa,Eq,qb,ibq, -5b
4b DftTft 5q,i33,iq3,ibq,2,i33,iq4,ibq,5,qb, -20
47 DftTft 152, 7 E, 3E, 147, 253,0, 104, lb2, 4 b, 7 b, -44
4a DftTft 205,251,0,lb2,0,0,iaq,E34,E55,D, -31
4q DftTft 3E, ElO, S55, E3E,EE4, EE, E0a,E4 5, lb0,5q, -51
50 DftTft 3E,ab,E50,0,173,57,E,3E,iq0,E51, -4
51 DftTft 0,173,5a,E,3E,iq0,E51,0,3E,75, -31
5E DftTft E50,0,3E,33,E50,0,E4D,a7,3E,220, -13
53 DftTft 24q,0,32,23q,251,0,144,4b,32,223, - 40
54 DftTft 251, 0,32, 220, 24q,0,3E,23q, 251,0, -51
55 DftTft 144,35,32,223,251,0,32,225,255,24 0,-33
286 MACHINE LANGUAGE FOR COMMODORE MACHINES
5t DRTa LD,lbfc,3fl,5Dfl,5t,lfc5,lR5,iq7,iq3,lfc5, -2E
5 a DATfi 0, 32, 163, E51, 0,32, 31, ESQ, 0,E4
5R DATA EE4,7b,flD,E5E,0,3E,E3R,E51,D,l^^, - ^E
bD DATA 3,3E,ED,E5D,0,3E,75,E5D,D,EDfl,-'^3
bl DATA 7,3E,E3q,E51,D,l'^4,E35,lt,q,fl,133, -Efl
fcE DATA Eq,3E,EED,E4R,D,3E,53,E5D,0,SDfi, -Ifl
t3 DATA E^ a, 7 fc, ESq, E4 S,D,3E,ED7, ESS, EDI, 13, - EE
l,A DATA E4D,lE,E01,3E,E0a,EDq,3E,E3q,E51,D, -57
tS DATA 144,3,3E,En,E5D,D,17'^,b3,E,154, - ^b
DATA lE0,17 3,57,E,7E,17 3,5a,E,7E,173, -35
b7 DATA 5S,E,7E,173,fcD,E,174,fcl,E,17E, -55
ba DATA tE,E,fc^,17'^,fc3,E,15<,ina,E,lbD, -5fc
DATA lfcD,l,13E,iab,13E,ia5,13b,13E,ia3,13E, -E7
7D DATA l<4,13E,1^7,lbq,fc'^ ,133,ia7,lbR,E,133, -iq
71 DATA iaa,3E,ED7,E55,S01,3E,E^D,E^q,EDl,13,-^E
7E DATA E^D,5b,EDl,3^,EDa,ED,3E,ED7,E5S,EDl, -35
73 DATA 3<,E<D,lfc,EDl,13,E^D,^l,1^5,ia7,E3D,-3q
7 A DATA ia3,EDD,iqE,lt,EDfl,E3b,7t,aD,E5E,D,-lfl
7 5 DATA 3E, E07, ESS, EDI, 13, E^ □, EE, EDI, 44, SOa, -51
7b DATA EED,3E,E5^,E51,D,<1,15,E4D,E33,ED1, -^t
77 DATA 3, E4 □, EER, 133, lab, 3 E,ED7, ESS, EDI, 13, -<5
7a DATA qt, IDa,^ a, 3, lDa,5D, 3, 3E, EE, ESI, -tD
7q DATA D,EDa,ElE,lfcq,D,D,3E,lll,E51,D, -37
aD DATA Its, 1^^,41, It, EDa, EDI, 7 b,EEq,E^q,D, - EE
ai DATA 3E, EE, E51, D, EOl, EDa, iqi, 3E, E3q, -^a
aE DATA E51,D,3E,EE3,ES1,D,3E,ED7,S55,ED1, -ES
a3 DATA ^4,SDa,17a,3E,E3q,ESl,D,ltS,iq3,133,-7
a^ DATA 17<,lt5,iq^,133,17S,3E,EE3,ESl,D,3E, -34
as DATA ED7,E5S,EDl,13,EDa,157,3E,114,ESl,D, -3t
at DATA 7t,EEq,E4q,D,ltS,iq4,3E,iqD,251,D, -3q
87 DATA lt5,iq3,7E,74,7<,7<,74,3E,E14,E51, -13
afi DATA D,17D,1D4,41,1S,3E,E14,ES1,D,7E, - It
aq DATA 13a,3E,ElD,ESS,lD<,7t,ElD,E55,q,4a, -q
qa DATA EDl,Sa,144,E,lDS,t,qt,ltE,E,iai, - 3D
qi DATA iqE,7E,iai,iq4 ,i4q,iqE,iD4,i4q,iq4,EDE, -ES
qE DATA EDa,E43,qt,3E,ES4,E51,D,144,E,133, - 3D
q3 DATA iq4,3E,ES<,E51,0,144,E,133,iq3,qt, -43
q4 DATA ltq,D,D,133,4E,3E,EED,E4q,D,EDl, -3q
qS DATA 3E,EDa,q,3E,EED,E4q,D,EDl,3E,EDa, - ES
qt DATA 14,E4,qt,3E,37,E5E,D,lD,lD,lD, -tE
q7 DATA lD,133,4E,3E,EED,E4q,D,3E,37,E5E, -3q
qa DATA □,S,4E,St,qt,EDl,5a,144,E,lDS, -Et
APPENDIX H — A DO-IT-YOURSELF SUPERMON
287
qq DATA fl,^l,15,qt,qfc,3E,55D,E4q,D,aDl,-tE
IDO DATA 3E,E^D,E4q,qb,lbq,0,D,l^l,D,0, -SS
IDl DATA 1,3E,^7,EEE,D,3E,5,E5E,0,3E, -Eq
lOE DATA E<E,E51,D,144,q,qb,3E,EED,E^q,0, -Efl
1D3 DATA 3E, E3q,E51,D, 17 t,EEE, 174, b3,E,15<, -35
104 DATA lfcq,t3,3E,ElD,E55,7t,SSq,E4q,D,3E, - 4fl
IDS DATA l<3,E53,Q,EDE,EDfl,E5Q,qt,lt5,iq5,lt4, -IE
IDt DATA iqb,5t,E33,E,17t,l,13fc,5t,EEq,iq3, -tl
1D7 DATA 133,3D,15E,EEq,iq4,lfcfl,5,3D,qt.,3E, -41
IDA DATA 55 / E5E, 133, 3E,lt5,iq4, 133, 33, IfcE, - EE
IDq DATA □,D,13<,<D,lbq,147,3E,ElD,E55,lfcq, -3E
IID DATA EE, 133, Eq,3E,lt5,E5E,0,3E, 5, E53, -E
111 DATA □,133,iq3,13E,iq4,iqa,Eq,EDfl,E4E,lfcq, - It.
HE DATA 14 5,3E,E10,E55,7E3,EEq,E4q,D,lt0,44, -41
113 DATA 3E,flb,E5D,0,3E,l<3,E53,D,3S,lfl3, -E3
114 DATA E51,D,3E,14 3,E53,D,ltE,D,D,ltl, -E5
115 DATA iq3,3E,EQ,S53,D,7E,3S,qD,E53,D, -E5
lit DATA lD4,3E,llE,E53,D,ltE,t,SE4,3,EDa, -43
117 DATA lfl,lb4,31,E4D,14,lt5,4E,EQl,E3E,177, -ID
llfi DATA iq3,17t,Efl,3E,E53,E5E,0,13t,EDa,E4E, -15
liq DATA t,4E,144,14,lflq,54,E55,D,3E,lfl7, -3
lEO DATA E53,D,lflq,fcD,E55,0,E4D,3,3E,lfl7, -E4
lEl DATA E53,D,E0E,EDfi,E13,qb,3E,fl,E53,D, -45
lEE DATA 17D,E3E,E0a,l,E0D,15E,3E,E53,E5E,n, -3q
1E3 DATA 13a,134,Ea,3E,iqO,E51,D,lLb,Ea,qt, -47
1E4 DATA lt5,31,5t,lb4,iq4,17D,lfc,l,13b,lDl, -53
1E5 DATA iq3,144,l,EDD,qt,lba,74 ,14 4 ,ll,74,-El
lEb DATA 17t,E3,EDl,34,E4D,iq,41,7,q,lEa, -t3
1E7 DATA 74, 17D,iaq,SEq,E54, 0,17^,4, 74, 74, -5E
lEa DATA 74,74,41,15,E0a,4,lbD,lSfl,ltq,D, - ED
lEq DfiTA 0,17D,iaq,41,E55,D,133,4E,41,3, -tE
13D DATA 133,31,15E,41,143,17D,15E,lt0,3,EE4, -3t
131 DATA 13a, E4 0,11,74,144, a, 74,74, q,3E,-t,
13E DATA 13t,EDa,E5D,EDD,13t,EDa,E4E,qt,177,iq3, -Eq
133 DATA 3E,E53,E5a,D,lbE,l,3E,qE,E5E,D,-lt
134 DATA iqfc,31,EDD,144,E41,lfcE,3,iqE,4,144, -la
135 DATA E4E,qb,lba,ia5,b7,E55, 0,133,4 0, 185,-13
13 1 DATA 131,E55,D,133,41,ltq,0,D,lbD,5, -3
137 DATA t,41,3a,40,4E,13t,SDa,E4a,lD5,fc3,-E7
.13a DATA 3S,ElD,E55,E0E,EDfi,E3t3,lbq,3E,EDa,ll, - It
13q DATA ltq,13,3t,iq,lt,5,3E,ElD,E55,ltq, -30
14 DATA 10,7t,E10,E55,3E,55,S5E,0,ltq,3, -El
141 DATA 133,Eq,3E,EE0,E4q,0,3E,53,E50,0, -4E
288 MACHINE LANGUAGE FOR COMMODORE MACHINES
lAE DATA EU&,EA&,H=S,32,l33,m3,li=S,33,l33,l'=]A, -A3
1A3 DATA 7fc,134,E5E,D,iq7,<D,E'5 0,3,35,210, -fcD
lAA DATA a55,qfc,3E,55,E5E,D,3E,SE3,251,D, -57
IAS DATA l^E,17,E,lbE,3,3E,47,E5E,D,7E, -43
lAh DATA EDE,EDfl,E4q,ltE,3,lD<,5t,E33,t3,ltD, -37
1A7 DATA 5,74,110,17,E,llD,lfc,S,13fc,EDfl, - lb
14 fl DATA E4t,E0E,EDfi,E37,lfcE,E,3E,ED7,E55,EDl, -31
14 H DATA 13,S4D,3D,E01,3E,E4D,E4 5,3E,EED,E54, -q
15D DATA □,17t.,15,3E,lfl,E5E,0,lb4,iq3,13E, -q
151 DATA iq4,133,iq3,ltq,4fl,157,lb,E,E3E,157, -47
15E DATA lb,E,E3E,EDfl,Eiq,134,4 0,ltE,D,0, - ID
153 DATA 134,3a,E4D,4,E3D,3fl,E4D,117,ltE,0, -q
154 DATA □,134,Eq,lb5,3fl,3E,ED,E53,D,lfct, - 4fi
155 DATA 4E,134,41,17D,lflfl,t7,E55,D,lflq,131, -47
15 1 DATA E55,D,3E,iq7,E54,D,EDfi,EE7,ltE,t, -54
157 DATA EE4/3,EDa,E5,lt4,31,E4D,El,lb5,4E, -fc3
15fl DATA EDl,E3E,ltq,4fl,17fc,33,3E,ED3,E54,D, -3q
15q DATA E0fl,E04,3E,ED5,E54,D,EDfl,iqq,13b,EDfi, -Efl
ItD DATA E35,t,4E,144,ll,lflfl,b0,E55,D,lflq, -15
Itl DATA 54,E55,D,3E,iq7,E54,D,EDfl,lfll,EDE, -1
ItE DATA Enfi,Enq,E4n,in,3E,iqt,E54,n,EDa,i7i, -51
lt3 DATA 3E,iqt,E54,D,EDfi,lbb,lb5,4D,iq7,Eq, -15
lt4 DATA EDfl,ltD,3E,EE3,E51,D,lt4,31,E4D,4D, -t
lt5 DATA lt5,41,E01,157,E0a,Et,3E,qq,E5E,D, -35
Itt DATA 144,10,15E,EDfl,4,lt5,30,lt,lD,7b, - 40
lt7 DATA fiD,E5E,D,EDD,SDa,S5D,lt5,3D,lt,S4b, -q
It a DATA lt4,31,EQa,3,lfl5,iq4,D,0,14 5,iq3, -tE
Ibq DATA 13t.,E0a,E4a,lb5,3a,145,iq3,3E,5,E53, -41
17D DATA □,133,iq3,13S,iq4,lb0,b5,3E,at,E5D, -34
171 DATA □,3E,143,E53,0,3E,ia3,E51,D,3E, -5t
17E DATA 143,E53,0,7b,iqa,E53,D,lta,3E,ED3, -Eq
173 DATA E54,Q,EDa,17,15E,E4D,14,134,Ea,ltt, -t3
174 DATA Eq,EEl,lt,E,a,E3E,134,Eq,ltt,Ea, - to
175 DATA 40,qt,EDl,4a,144,3,E01,71,qt,5t, -30
i7t DATA qt,b4,E,tq,3,Eoa,a,t4,q,4a, -14
177 DATA 34,tq,51,EDa,a,t4,q,t4,E,fcq, -50
17a DATA 51,E0a,a,b4,q,fc4,E,tq,17q,EDa, -47
17q DATA a,fc4,q,D,D,34,ta,51,E0a,14D, -la
laO DATA t.a,0,D,17,34,fca,51,EDa,14D,fea, -5
lai DATA 154,lt,34,ba,51,EDa,a,b4,q,lL, -EO
laE DATA 34,ta,5i,EDa,a,t4,q,qa,iq,iED,-tE
ia3 DATA ltq,0,0,33,lEq,13D,0,D,D,D, -41
ia4 DATA aq,77,145,14t,134,74,133,157,44,41,-3q
APPENDIX H — A DO-IT-YOURSELF SUPERMON
289
ifiB DATa -^4, 35, ^0,3^, an, 0,n,fla,3t,3t, - EE
lat DATA □,D,Sa,13a,Ea,3 5,q3,13q,E7,lfcl, - ID
Ifi? DATA 157,13a,ER,35,157,13q,Eq,lbl,D,D,-H
laa DATA <l,E5,174,lD5,lba,E5,35,3b,fl3,E7,-fc<
laq DATA 35,3b,a3,E5,lbl,D,D,Eb,qi,qi, -E<
iqO DATA lb5,lD5,3b,3t,17^,174,lLa,17 3,41,0,-3
IRl DATA D,lE^,D,D,El,15t,lD'=1,15b,lb5,lD5,-ED
iqa DATA ^l,a3,13E,iq,5S,17,lb5,lD5,35,lfcD, -Eb
iq3 DATA Eib,qa,qD,7E,3a,qa,i'^fi,i3fc,a^,ba,-ED
iq/i DATA EDD,fl^,lD^,ba,53E,14a,D,D,iaD,a,-31
iqS DATA 13E,llb,lfln,<D,110,llt,S^4,ED4,7^,ll<,-3S
iqt DATA E4E,lt^,13a,D,D,17D,lbE,ltE,llt,llt, -11
iq7 DATA llb,114,tfl,lD^,17a,5D,17a,D,D,34,-3D
iqa DATA □, □,Et,Et, 3a, 3a, 114, 114, 13fc, EDO, -E7
iqq DATA iqt,EDE,3a,7E,ta,ba,ifcE,E00,5a,5q, -35
EDO DATA aE,77,71,aa,7fc,a3,ta,44,fc5,ED'^ , -5q
EOl DATA E5D,D,iqi,E5D,0,qt,E50,Q,134,S50, -E5
EDE DATA □, EE4 , E5D , , 14 , E51 , D , lit , E51 ,□ , -E3
ED3 DATA 135 , E51 , □ , lED , E5E , □ , ItO , E53 , □ , iq4 , - iq
ED4 DATA E53,0,EEa,E4q,Q,157,E4q,D,13q,E4q, -t3
ED5 DATA □,13,3E,3E,3E,aD,t7,3E,3E,a3,-3
EDt DATA aE,3E,fc5,fc7,3E,aa,aE,3S,aq,aE, - It
E07 DATA 3E,a3,aD, -5q
E55 DATA EDfl
3D0 M=t3
310 READ X:L = PEEK(M) :H = L = E55:IF H THEN L = X
3ED V = R()L:S = (T(>t3 AND R)0 AND V)
33D IF V THEN T = L:IF NOT S THEN R = R + 1:S = R()L
3AD T= {T*3 + X) ANDt3
350 IF S THEN PRINT "ERROR LINE";R:E=-1
3tD R=L:IF NOT H GOTO 31D
370 IF E THEN STOP
3aD PRINT"HERE WE GO" : X =- 1 : RESTORE : B = ED4q : FOR A = l
TO qqqq
3qD IF X)=D THEN POKE B,X:B = B + 1
ADO READ X:L = PEEK(M) :IF L(E55 THEN NEXT A
AID POKE 45,lt:P0KE 4t,lt:CLR
290
MACHINE LANGUAGE FOR COMMODORE MACHINES
The Commodore 1 28 Monitor and
SUPERMON +
The built-in maciiine language monitor of the Commodore 128 is quite
close to SUPERMON. With the release of the C128, a new version of
SUPERMON (called SUPERMON + ) has been produced so as to match
the commands and syntax of the 128's monitor. Versions are available
for Commodore 64 (including the 1 28 in 64 mode) and for VIC-20.
The principal features of the new monitor, as compared to SUPERMON,
are as follows:
— Syntax is somewhat easier. Leading zeros need not be typed on any number.
Spacing between addresses is non-critical.
— Conversion between number systems is built-in. The user may employ the
following prefixes: $ for hexadecimal; + for decimal; & for octal (rarely used
with present day microcomputers); and % for binary. Any value or address
may be entered in any number system. If a number is typed In alone, with
Its prefix, it will be shown converted to all other number systems.
— When the A(assemble) command is given, the object code immediately ap-
pears on the line just typed.
—The disl< may be controlled, interrogated or cataloged by means of the disk
"@" command.
— Memory displays contain information on the ASCII equivalents of the bytes
displayed.
— Commands such as M (memory display) and D allow: two addresses, to
display a specified range; one address, to display a fixed range; or no ad-
dresses, to continue the display from that shown previously.
Program SUPERMON -i- , for VIC-20 and Commodore 64, is not a monitor;
it is a monitor generator that will make a machine language monitor for
you. SUPERMON + finds a likely spot in memory and then plunks the
MLM there so as to fit into the most suitable place.
If you are using a VIC-20 or Commodore 64 configuration, load SUPER-
MON-!- and type BUN. It will write an MLM for you, and call it up. Now,
exit back to BASIC and command NEW. You do not want the MLM builder
any more (it's done the job) and you do not want the danger of building
two — or more — MLM's. Get rid of the generator program. Any time you
need to use the MLM, give SYSfl.
If you are using the Commodore 128 in its C128 mode, there's no need
to load a monitor. Just command MONITOR and you are there.
APPENDIX H — C128 MONITOR AND SUPERMON +
291
The C128 monitor and SUPERMON + use the following commands:
R— to display (and change) registers
M— to display (and change) memory
S — to save memory to disk or tape
L — to load from disk or tape
G— to go to an ML program
X— to exit to BASIC
a — to assemble
D— to disassemble
The above commands are the only ones used within the text of the book.
Other commands which are available are:
F— fills memory with fixed contents:
F IflDD IflFF □□
H — hunts for a memory pattern:
H OaOO IflOO 50 D2 FF
T — transfers a block of memory to a new location:
T DflDD DBFF &QQO
C — compares a block of memory to another.
C □flOD OCDD aODD
J— calls a subroutine directly from the monitor.
J 0330
@ — alone, gets the disk status report.
@, $□ — gets the disk directory.
@, SO : SAMPLE— sends a command to the disk (in the example, scratch file
SAMPLE).
The @ symbol may be followed by a number to reference a drive other
than unit 8.
I
lA Chip
Information
Tfie following material has been adapted from manufacturer's specifica-
tions. The information is not essential to machine language programming,
but can be a great help for further study. Some of these specifications are
not widely published and contain "hard to get" information.
6520 PI a, peripheral interface adaptor
6522 VIA, versatile interface adaptor
6525 TPA, tri port adaptor
6526 CIA, complex interface adaptor
6545 CRTC, CRT controller
6560 VIC video interface chip
6566 VIC-E video interface chip
6581 SID sound interface chip
[Essentially manufacturer's specs, less hardware details]
293
294 MACHINE LANGUAGE FOR COMMODORE MACHINES
6520 Peripheral Interface Adaptor (PIA)
The 6520 is an I/O device wliicli acts as an interface between tlie micro-
processor and peripherals such as printers, displays, keyboards, etc. The
prime function of the 6520 is to respond to stimulus from each of the two
worlds it is serving. On the one side, the 6520 is interfacing with peripherals
via two eight-bit bi-directional peripheral data ports. On the other side, the
device interfaces with the microprocessor through an eight-bit data bus.
In addition to the lines described above, the 6520 provides four interrupt
input/peripheral control lines and the logic necessary for simple, effective
control of peripheral interrupts.
MICRO
PROCESSORS -<
650 X
8 BIT \
DATA )
BUS /
(
CONTROL
( control)
6520
8 BIT
DATA
PORT
8 BIT
DATA
PORT
PERIPHERAL
DEVICES-
SPRINTERS,
DISPLAYS,
ETC.
CONTROL )
Figure 1.1
The functional configuration of the 6520 is programmed by the micro-
processor during systems initialization. Each of the peripheral data lines
is programmed to act as an input or output and each of the four control/
interrupt lines may be programmed for one of four possible control modes.
This allows a high degree of flexibility in the overall operation of the in-
terface.
Data Input Register
When the microprocessor writes data into the 6520, the data which ap-
pears on the data bus is latched into the Data Input Register. It is then
transferred into one of six internal registers of the 6520. This assures that
the data on the peripheral output lines will not "glitch," i.e., the output lines
will make smooth transitions from high to low or from low to high and the
voltage will remain stable except when it is going to the opposite polarity.
APPENDIX I
295
Control Registers fCRA and CRB)
Figure 1.2 illustrates tlie bit designation and functions in the Control Reg-
isters. Tlie Control Registers allow the microprocessor to control the op-
eration of the interrupt lines (CAl, CAE, CBl, CBE), and peripheral
control lines (CR2, CBE). A single bit in each register controls the ad-
dressing of the Data Direction Registers (DDRA, DDRB) and the Output
Registers, {0R&, ORB) discussed below. In addition, two bits (bit Ed and
7 ) are provided in each control register to indicate the status of the i nterrupt
input li nes (CAl, CAS, CBl, CB2). These interrupt status bits (IRQA,
IRQB) are normally interrogated by the microprocessor during the inter-
rupt service program to determine the source of an acti ve interrupt . These
are the interrupt lines which drive the interrupt input (IRQ, NMI) of the
microprocessor. The other bits in CRA and GRB are described in the
discussion of the interface to the peripheral device.
The various bits in the control registers will be accessed many times during
a program to allow the processor to enable or disable interrupts, change
operating modes, etc. as required by the peripheral device being con-
trolled.
Data Direction Registers fDDRA, DDRB;
The Data Direction Registers allow the processor to program each line in
the 8-bit Peripheral I/O port to act as either an input or an output. Each
bit in DDR A controls the corresponding lines in the Peripheral A port and
each bit in DDRB controls the corresponding line in the Peripheral B port.
Placing a " " in the Data Direction Register causes the corresponding
Peripheral I/O line to act as an input. A " 1 " causes it to act as an output.
The Data Direction Registers are normally programmed only during the
system initialization routine which is performed in response to a Reset
signal. However, the contents of these registers can be altered during
system operation. This allows very convenient control of some peripheral
devices such as l<eyboards.
Periplieral Output Registers fOR A, ORB;
The Peripheral Output Registers store the output data which appears on
the Peripheral I/O port. Writing an "0" into a bit in OR A causes the
corresponding line on the Peripheral A port to go low (< . 4 V) if that
line is programmed to act as an output. A " 1 " causes the corresponding
output to go high. The lines of the Peripheral B port are controlled by ORB
in the same manner.
296
MACHINE LANGUAGE FOR COMMODORE MACHINES
Interrupt Status Control
The four interrupt/peripheral control lines (CRl, CRE, CBl, CBE) are
controlled by the Interrupt Status Control (A, B). This logic interprets the
contents of the corresponding Control Register, detects active transitions
on the interrupt inputs and performs those operations necessary to assure
proper operation of these four peripheral interface lines.
Reset (R'ES)
The active low Reset line resets the contents of all 6520 registers to a
logic zero. This line can be used as a power-on reset or as a master reset
during system operation.
Interrupt Request Une fl R Q A, I R Q Bj
The active low Interrupt Request lines (IRQR and IRQB) act to interrupt
the microprocessor either directly or through external interrupt priority cir-
cuitry.
Each Interrupt Request line has two interrupt flag bits which can cause
the Interrupt Request line to go low. These flags are bits t and 7 in the
two Control Registers. These flags act as the link between the peripheral
interrupt signals and the microprocessor interrupt inputs. Each flag has a
corresponding interrupt disable bit which allows the processor to enable
or disable the interrupt from each of the four interrupt inputs (CRl, CAE,
CBl, CBE).
The four interrupt flags are set by active transitions of the signal on the
interrupt input (CRl, CRE, CBl, CBE). Controlling this active transition
is discussed in the next section.
Control of IRQA
Control Register R bit 7 is always set by an active transition of the CRl
interrupt input signal. Interrupting from this flag can be disabled by setting
bit □ in the Control Register R (CRR) to a logic □. Likewise, Control
Register R bit t can be set by an active transition of the CRE interrupt
input signal. Interrupting from this flag can be disabled by setting bit 3 in
the Control Register to a logic □.
Both bit t and bit 7 in CRR are reset by a "Read Peripheral Output
Register A" operation. This is defined as an operation in which the pro-
cessor reads the Peripheral A I/O port.
APPENDIX I
297
Control of IRQB
Control of IRQB is perfo rmed in exactly the same manner as that de-
scribed above for IRQR. Bit 7 in CRB is set by an active transition on
CBl; interrupting from this flag is controlled by CRB bit 0. Lil<ewise, bit
t in CRB is set by an active transition on CBE; interrupting from this flag
is controlled by CRB bit 3.
Also, both bit L and bit 7 are reset by a "Read Peripheral B Output
Register" operation.
Summary
IRQAgoeslowwhen CRa-7 = 1 and CRfi-D = lor when CRR-fc
= 1 and CRft-3 = 1.
IRQB goes low when CRB -7 = 1 and CRB -0 = 1 or when CRB - 1
= 1 and CRB -3 = 1.
It should be stressed at this point that the flags act as the link between
the peripheral interrupt signal and the processor interrupt inputs. The in-
terrupt disable bits allow the processor to control the interrupt function.
Peripheral I/O Ports
Each of the Peripheral I/O lines can be programmed to act as an input or
an output. This is accomplished by setting a " 1 " in the corresponding
bit in the Data Direction Register for those lines which are to act as outputs.
A " □ " in a bit of the Data Direction Register causes the corresponding
Peripheral I/O lines to act as an input.
Interrupt Input/ Peripheral Control Lines (CAl,
CAE, CBl, CBE
The four interrupt inpuf peripheral control lines provide a number of special
peripheral control functions. These lines greatly enhance the power of the
two general purpose interface ports (Pan-PR7, PBD-PB7).
Peripheral A Interrupt Input/ Peripheral Control
Unes (CM, CA2)
Ckl is an interrupt input only. An active transition of the signal on this
input will set bit 7 of the Control Register a to a logic 1 . The active transition
can be programmed by the microprocessor by setting a " Q " in bit 1 of
298
MACHINE LANGUAGE FOR COMMODORE MACHINES
the CRA if the interrupt flag (bit 7 of CBA) is to be set on a negative
transition of the C AI signal or a " 1 " if it is to be set on a positive transition.
Setting the interrupt flag will interrupt the processor through IRQA if bit
□ of CR a is a 1 as described previously.
CAE can act as a totally independent interrupt input or as a peripheral
control output. As an input (CRA , bit 5 = D) it acts to set the interrupt
flag, bit t of CRA, to a logic 1 on the active transition selected by bit A
of CRA.
These control register bits and interrupt inputs serve the same basic func-
tion as that described above for CAl. The input signal sets the interrupt
flag which serves as the link between the peripheral device and the pro-
cessor interrupt structure. The interrupt disable bit allows the processor
to exercise control over the system interrupts.
In the Output mode (CR A , bit 5 = 1), CA2 can operate independently
to generate a simple pulse each time the microprocessor reads the data
on the Peripheral A I/O port. This mode is selected by setting CRA, bit A
to a "□" and CRA, bit 3 to a "1". This pulse output can be used to
control the counters, shift registers, etc. which mal<e sequential data avail-
able on the Peripheral input lines.
A second output mode allows CAE to be used in conjunction with CAl
to "handshake" between the processor and the peripheral device. On the
A side, this technique allows positive control of data transfers from the
peripheral device into the microprocessor. The CAl input signals the
processor that data is available by interrupting the processor. The pro-
cessor reads the data and sets CAE low. This signals the peripheral device
that it can make new data available.
The final output mode can be selected by setting bit ^ of CRA to a 1. In
this mode, CAE is a simple peripheral control output which can be set
high or low by setting bit 3 of CRA to a 1 or a □ respectively.
Peripheral B Interrupt Input/Peripheral Control
Unes (CBl, CB Ej
CBl operates as an interrupt input only in the same manner as CAl. Bit
7 of CRB is set by the active transition selected by bit of CRB. Likewise,
the CBE input mode operates exactly the same as the CAE input modes.
The CBE output modes, CRB, bit 5 = 1, differ somewhat from those
of CAE. The pulse output occurs when the processor writes data into the
Peripheral B Output Register. Also, the "handshaking" operates on data
transfers from the processor into the peripheral device.
APPENDIX I
299
7
6
5 4 3
2
1 (J
CRA
IRQA1
IRQA2
CA2 CONTROL
DDRA
ACCESS
CA1 CONTROL
, * .
, ^ .
7
6
5 4 3
2
1
CRB
IRQBl
IRQB2
CB2 CONTROL
A
DDRB
ACCESS
CB2 CONTROL
, * ^
f \
Figure L2
6545-1 CRT Controller (CRTC)
Concept
The 6545-1 is a CRT Controller intended to provide capability for inter-
facing the 6500 microprocessor family to CRT or TV-type raster scan
displays.
Horizontal Total (RO)
This 8-bit register contains the total of displayed and non-displayed char-
acters, minus one, per horizontal line. The frequency of HSYNC is thus
determined by this register.
Horizontal Displayed (R1)
This 8-bit register contains the number of displayed characters per hori-
zontal line.
Horizontal Sync Position (R2)
This 8-bit register contains the position of the HSYNC on the horizontal
line, in terms of the character location number on the line. The position
of the HSYNC determines the left-to-right location of the displayed text on
the video screen. In this way, the side margins are adjusted.
300
MACHINE LANGUAGE FOR COMMODORE MACHINES
Horizontal and Vertical SYNC Widths (R3)
This 8-bit register contains the widths of both HSYNC and VSYNC, as
follows:
7
6
5
4
3
2
1
8 4 2 1 8 4 2 1
' 1 ' ' 1 '
VSYNC |WIDTH* HSYNC| WIDTH
(NUMBER OF SCAN LINES) (NUMBER OF CHARACTER
CLOCK TIMES)
*IF BITS 4-7 ARE ALL "0"; THEN VSYNC WILL BE 16 SCAN LINES WIDE.
Control of these parameters allows the 6545-1 to be interfaced to a variety
of CRT monitors, since the HSYNC and VSYNC timing signals may be
accommodated without the use of external one-shot timing.
Vertical Total (R4)
The Vertical Total Register is a 7-bit register containing the total number
of character rows in a frame, minus one. This register, along with R5,
determines the overall frame rate, which should be close to the line fre-
quency to ensure flicker-free appearance. If the frame time is adjusted to
be longer than the period of the line frequency, then RES may be used
to provide absolute synchronism.
Vertical Total Adjust (R5)
The Vertical Total Adjust Register is a 5-bit write only register containing
the number of additional scan lines needed to complete an entire frame
scan and is intended as a fine adjustment for the video frame time.
Vertical Displayed (R6)
This 7-bit register contains the number of displayed character rows in each
frame. In this way, the vertical size of the displayed text is determined.
APPENDIX I
301
vt
'5)
CO
to
1^
oc
5
Q
■O
o
o
E
a
0)
to
o
DC 2
o
X
n
X
o8
□ »-
CO O
idVH "Jt^ -JJ^ *^t^ -JT^i
of
2 Q CO o
N N N 5
O O O CO
X X X >
O T- OJ CO
DC CC DC DC
■ X ■ ■ ■ X m
■ X ■ ■ ■ X m
X X X X ■ X X
(0 CO
o 0) o o
OC O DC DC
d □ d d
CO _ CO CO
i— d 1— i—
CO (0 CO CO
£ (3 £ x:
O CO O O
=fe * * *
=i g
o c
CO g
* CO
CO
c
o
> >
CO
0) o ^
CO ^
"5_ " <=
. . fl) c
■c -o §
0) O o
> 2 CO O
>
- 0) iS
c CO
o
CO
o
in CD h- CO o) 1-
GC CC X DC DC DC DC
X ■
X X
X X
X ■ X
X ■ X
c
CO
o
CO
X 3;
T3 T3
T3 T3 _
< < §
■c -c s
"O CO CO CO
iS w 55 £
o w w o
CO Q-Q. 2
3 CO (0 3
O Q b o
o ci) d)
w DC DC
1? =
2 £ £
o □ □
1- cj CO lo to
E X X E £ E E
CO
CO
3
Si
CO
15
T3
0)
CD
>
o
c
CO
(D
O
TJ
JZ
o
5
CO
X
Q.
CD
O
X
I
5
(0 .
CO ®
.iS CO
^
CO ^
is CO
o> •«
c 2
CO Q.
O
DC j=
*J —
*- s ■§
^ CO ^
to 3 -
.£ c CO
3 O
CO CO L.
S £
^li
« w 5S "
© =
B Q C3 «
Z p X
302
MACHINE LANGUAGE FOR COMMODORE MACHINES
Vertical Sync Position (R7)
This 7-bit register is used to select the character row time at which the
VSYNC pulse is desired to occur and, thus, is used to position the dis-
played text in the vertical direction.
MoQfe Control (R8)
This register is used to select the operating modes of the 6545-1 and is
outlined as follows:
7
6
5
4
3
2 1 1
-INTERFACE MODE CONTROL
BIT
OPERATION
1
X
NON INTERLACE
X
1
INVALID (DO NOT USE)
VIDEO DISPLAY RAM ADDRESSING
"0" FOR STRAIGHT BINARY
"1" FOR ROW/COLUMN
MUST PROGRAM TO "0"
DISPLAY ENABLE SKEW
"0" FOR NO DELAY
"1" TO DELAY DISPLAY ENABLE
ONE CHARACTER TIME
' CURSOR SKEW
"0" FOR NEW DELAY
"1" TO DELAY CURSOR ONE
CHARACTER TIME
[]-NOT USED
Figure 1.3
Scan Line (R9)
This 5-bit register contains the number of scan lines per character row,
including spacing.
APPENDIX I
303
Cursor Start (R10) and Cursor End (R11)
These 5-bit registers select the starting and ending scan lines for the
cursor. In addition, bits 5 and 6 of R1 are used to select the cursor mode,
as follows:
CURSOR MODE
No Blinking
No Cursor
Blink at 1/16 field rate
Blink at 1/32 field rate
Note that the ability to program both the start and end scan line for the
cursor enables either block cursor or underline to be accommodated.
Registers R14 and R15 are used to control the character position of the
cursor over the entire 16K address field.
Display Start Address High (R12) and Low
(R13)
These registers together comprise a 14-bit register whose contents is the
memory address of the first character of the displayed scan (the character
on the top left of the video display, as in Figure 1). Subsequent memory
addresses are generated by the 6545-1 as a result of CCLK input pulses.
Scrolling of the display is accomplished by changing R12 and R13 to the
memory address associated with the first character of the desired line of
text to be displayed first. Entire pages of text may be scrolled or changed
as well via R12 and R13.
Cursor Position l-ligli (R14) and Low (R15)
These registers together comprise a 1 4-bit register whose contents is the
memory address of the current cursor position. When the video display
scan counter (MA lines) matches the contents of this register, and when
the scan line counter (RA lines) falls within the bounds set by R10 and
R1 1 , then the CURSOR output becomes active. Bit 5 of the Mode Control
Register (R8) may be used to delay the CURSOR output by a full CCLK
time to accommodate slow access memories.
LPEN Higli (R16) and Low (R17)
These registers together comprise a 14-bit register whose contents is the
light pen strobe position, in terms of the video display address at which
304 MACHINE LANGUAGE FOR COMMODORE MACHINES
the strobe occurred. When the LPEN input changes from low to high, then,
on the next negative-going edge of CCLK, the contents of the internal
scan counter is stored in registers R16 and R17.
6560 (VIC) Video Interface Chip
The 6560 Video Interface Chip (VIC) is designed for color video graphics
applications such as low cost CRT terminals, biomedical monitors, control
system displays and arcade or home video games. It provides all of the
circuitry necessary for generating color programmable character graphics
with high screen resolution. VIC also incorporates sound effects and A/D
converters for use in a video game environment.
Features
• Fully expandable system with a 16K byte address space
• System uses industry standard 8 bit wide ROMS and 4 bit wide RAMS
• Mask programmable sync generation, NTSC-6560, PAL-6561
• On-chip color generation (16 colors)
• Up to 600 independently programmable and movable background locations
on a standard TV
• Screen centering capability
• Screen grid size up to 192 Horizontal by 200 Vertical dots
• Two selectable graphic character sizes
• On-chip sound system including:
a) Three independent, programmable tone generators
b) White noise generator
c) Amplitude modulator
• Two on-chip 8 bit A/D converters
• ON-chip DMA and address generation
• No CPU wait states or screen hash during screen refresh
• Interlaced/Non-interlaced switch
• 16 addressable control registers
• Light gun/pen for target ^ames
• 2 modes of color operation
A: Interlace mode: A normal video frame is sent to the TV 60 times each
second. Interlace mode cuts the number of repetitions in half. When used
with multiplexing equipment, this allows the VIC picture to be blended with
a picture from another source.
APPENDIX I
305
To turn off: POKE 36864, PEEK(36864) AND 127
To turn on: POKE 36864, PEEK(36864) OR 128
B: Screen origin— horizontal: This determines the positioning of the
image on the TV screen. The normal value is 5. Lowering the value moves
the screen to the left, and increasing it moves the image to the right.
To change value: POKE 36864, PEEK(36864) AND 128 OR X
LOC
Hex
START VALUE-5K VIC
Bit
Function
Binary
Decimal
9000
00000101
5
ABBBBBBB
9001
00011001
25
CCCCCCCC
yuu<;
10010110
150
tlL/UUULJlJLJ
9003
V0101110
46 or 174
GEEEEEEF
9004
vwvvwv
V
GGGGGGGG
9005
11110000
240
HHHHIIII
9006
00000000
JJJJJJJJ
9007
00000000
KKKKKKKK
9008
11111111
255
LLLLLLLL
9009
11111111
255
MMiyiMMMMM
900A
00000000
NRRRRRRR
900B
00000000
OSSSSSSS
900C
00000000
900D
00000000
QUUUUUUU
900E
00000000
wwwwvwv
900F
00011011
27
XXXXYZZZ
A:
Interlace mode: 0=off,
N:
Bass sound switch
1 =on
0:
Alto sound switch
B:
Screen origin — horizontal
P:
Soprano sound switch
C:
Screen origin — vertical
Q:
Noise switch
D:
Number of video columns
R:
Bass Frequency
E:
Number of video rows
S:
Alto Frequency
F:
Character size:
T:
Soprano Frequency
= 8x8, 1 =8x16
U:
Noise Frequency
G:
Raster value
V:
Loudness of sounds
H:
Screen memory location
W:
Auxiliary color
1:
Character memory location
X:
Screen color
J:
Light pen — horizontal
Y:
Reverse mode = on,
K:
Light pen — vertical
1=off
L:
Paddle 1
Z:
Border color
M:
Paddle 2
306 MACHINE LANGUAGE FOR COMMODORE MACHINES
C: Screen origin— vertical: This determines tlie up-down placement of
the screen image. The normal value is 25. Lowering this causes the screen
to move up by 2 rows of dots for each number lowered, and raising it
moves the screen down.
To change value: POKE 36865, X
D: Number of video columns: Normally, this is set to 22. Changing this
will change the display accordingly. Numbers over 27 will give a 27 column
screen. The cursor controls are based on a fixed number of 22 columns,
and changing this number makes the cursor controls misbehave.
To change: POKE 36866, PEEK(36866) AND 128 OR X.
E: Number of video rows: The number of rows may range from to 23.
A larger number of rows causes garbage to appear on the bottom of the
screen.
To change: POKE 36867, PEEK(36867) AND 129 OR (X*2)
F: Character size: This bit determined the size of the matrix used for
each character. A here sets normal mode, in which characters are 8 by
8 dots. A 1 sets 8 by 16 mode, where each character is now twice as tall.
8 by 16 mode is normally used for high resolution graphics, where it is
likely to have many unique characters on the screen.
To set 8 by 8 mode: POKE 36867, PEEK(36867) AND 254
To set 8 by 16 mode: POKE 36867, PEEK(36867) OR 1
G: Raster value: This number is used to synchronize the light pen with
the TV picture.
H: Screen memory location: This determines where in memory the VIC
keeps the image of the screen. The highest bit in location 36869 must be
a 1. Bits 4-6 of location 36869 are bits 10-12 of the screen's address,
and bit 7 of location 36866 is bit 9 of the address of the screen. To
determine the location of the screen, use the formula:
S = 4* (PEEK(36866) AND 128) + 64* (PEEK(36869) AND 112)
Note that bit 7 of location 36866 also determines the location of color
memory. If this bit is a 0, color memory starts at location 37888. If this bit
is a 1 , color memory begins at 38400. Here is a formula for this:
C = 37888 + 4* (PEEK(36866) AND 128)
I: Character memory location: This determines where information on
the shapes of characters are stored. Normally this pointer is to the char-
acter generator ROM, which contains both the upper case/graphics or the
APPENDIX I
307
upper/lower case set. However, a simple POKE command can change
this pointer to a RAM location, allowing custom character sets and high
resolution graphics.
To change: POKE 36869, PEEK(36869) AND 240 OR X
(See chart on next page.)
J: Light pen horizontal: This contains the latched number of the dot
under the light pen, from the left of the screen.
K: Light pen vertical: The latched number of the dot under the pen,
counted from the top of the screen.
X
Location
Contents
Value
HEX
Decimal
8000
32768
Upper case normal characters
1
8400
33792
Upper case reversed characters
2
8800
34816
Lower case normal characters
3
8000
35840
Lower case reversed characters
4
9000
36864
unavailable
5
9400
37888
unavailable
6
9800
38912
VIC chip-unavailable
7
9C00
39936
ROM-unavailable
8
0000
unavailable
9
unavailable
10
unavailable
11
unavailable
12
1000
4096
RAM
13
1400
5120
RAM
14
1800
6144
RAM
15
1000
7168
RAM
L: Paddle X: This contains the digitized value of a variable resistance
(game paddle). The number reads from to 255.
M: Paddle Y: Same as Paddle X, for a second analog input.
N: Bass switch: If this bit is a 0, no sound is played from Voice 1. A 1
in this bit results in a tone determined by Frequency 1 .
To turn on: POKE 36874, PEEK(36874) OR 128
To turn off: POKE 36874, PEEK(36874) AND 127
O: Alto switch: See Bass switch.
308 MACHINE LANGUAGE FOR COMMODORE MACHINES
P: Soprano switch: See Bass switch.
Q: Noise switch: See Bass switch.
R: Bass Frequency: This is a value corresponding to the frequency of
the tone being played. The larger the number, the higher the pitch of the
tone.
The actual frequency of the sound in cycles per second (hertz) is deter-
nnined by the following formula:
Clock
Frequency = ^^^^
X is the number from to 127 that is put into the frequency register. If X
is 1 27, then use - 1 for X in the formula. The value of Clock comes from
the following table:
Register
NTSC (US TV's)
PAL (European)
36874
3995
4329
36875
7990
8659
36876
15980
17320
36877
31960
34640
To set: POKE 36874, PEEK(36874) AND 128 OR X
S: Alto Frequency: This is a value corresponding to the frequency of the
tone being played. The larger the number, the higher the pitch of the tone.
T: Soprano Frequency: This is a value corresponding to the frequency
of the tone being played. The larger the number, the higher the pitch of
the tone.
To set: POKE 36876, PEEK(36876) AND 128 OR X
U: Noise Frequency: This is a value corresponding to the frequency of
the noise being played. The larger the number, the higher the pitch of the
noise.
To set: POKE 36877, PEEK(36877) AND 128 OR X
V: Loudness of sounds: This is the volume control for all the sounds
playing. is off and 15 is the loudest sound.
To set: POKE 36878, PEEK(36878) AND 240 OR X
W: Auxiliary color: This register holds the color number of the auxiliary
color. The value can be from to 15.
APPENDIX I
309
To set: POKE 36878, PEEK(36878) AND 15 OR (16*X)
X: Screen color: A number from to 15 sets the color of the screen.
To set: POKE 36879, PEEK(36879) AND 15 OR (X*16)
Y: Reverse mode: A 1 in this bit indicates normal characters, and a
here causes all characters to be displayed as if reversed.
To turn on reverse mode: POKE 36879, PEEK(36879) AND 247
To turn off reverse mode: POKE 36879, PEEK(36879) OR 8
Z: Border color: A number from to 7 sets the color of the screen.
To set: POKE 36879, PEEK(36879) AND 248 OR X
6522 Versatile Interface Adapter (VIA)
The 6522 Versatile interface Adapter (VIA) provides two peripheral ports
with input latching, two powerful interval timers, and a serial-to-parallel/
parallel-to-serlal shift register.
6522 Versatile Interface Adapter Description
ADDRESS
DESCRIPTION
REGISTER
9110
Port B
AAAAAAAA
9111
Port A (with handshaking)
BBBBBBBB
9112
Data Direction B
CCCCCCCC
9113
Data Direction A
DDDDDDDD
9114
Timer #1 , low byte
EEEEEEEE
9115
Timer #1, high byte
FFFFFFFF
9116
Timer #1 , low byte to load
GGGGGGGG
9117
Timer #1 , high byte to load
HHHHHHHH
9118
Timer #2, low byte
IIIIIIII
9119
Timer #2, high byte
JJJJJJJJ
911A
Shift Register
KKKKKKKK
911B
Auxiliary Control
LLMNNNOP
911C
Peripheral Control
QQQRSSST
91 1D
Interrupt Flags
UVWXYZab
911E
Interrupt Enable
cedf ghij
911F
Port A (no handshaking)
kkkkkkkk
310 MACHINE LANGUAGE FOR COMMODORE MACHINES
PORT A I/O REGISTER
These eight bits are connected to the eight pins which make up port A.
Each pin can be set for either input or output.
Input latching is available on this port. When latch mode is enabled the
data in the register freezes when the CB1 interrupt flag is set. The register
stays latched until the interrupt flag is cleared.
Handshaking is available for output from this port. CB2 will act as a DATA
READY SIGNAL. This must be controlled by the user program. CB1 acts
as the DATA ACCEPTED signal, and must be controlled by the device
connected to the port. When DATA ACCEPTED is sent to the 6522, the
DATA READY line is cleared, and the interrupt flag is set.
PORT B I/O REGISTER
These eight bits are connected to the eight pins which make up port B.
Each pin can be set for either input or output. Handshaking is available
for both read and write operations. Write handshaking is similar to that on
PORT B. Read handshaking is automatic. The CA1 input pin acts as a
DATA READY signal. The CA2 pin (used for output) is used for a DATA
ACCEPTED signal. When a DATA READY signal is received a flag is set.
The chip can be set to generate an interrupt or the flag can be polled
under program control. The DATA ACCEPTED signal can either be a
pulse or a DC level. It is set low by the CPU and cleared by the DATA
READY signal.
DATA DIRECTION FOR PORT B
This register is used to control whether a particular bit in PORT B is used
for input or output. Each bit of the data direction register (DDR) is asso-
ciated with a bit of port B. If a bit in the DDR is set to 1 , the corresponding
bit of the port will be an OUTPUT. If a bit in the DDR is 0, the corresponding
bit of the port will be an INPUT.
For example, if the DDR is set to 7, port B will be set up as follows:
BITS NUMBER DDR PORT B FUNCTION
1 OUTPUT
1 1 OUTPUT
2 1 OUTPUT
3 INPUT
4 INPUT
5 INPUT
6 INPUT
7 INPUT
APPENDIX I
311
DATA DIRECTION REGISTER FOR PORT A
This is similar to tlie DDR for port B, except tliat it worl<s on PORT A.
E,F,G,H: TIMER CONTROLS
Tliere are two timers on tlie 6522 chip. The timers can be set to count
down automatically or count pulses received by the VIA. The mode of
operation is selected by the Auxiliary Control register.
TIMER T1 on the 6522 consists of two 8-bit latches and a 16-bit counter.
The various modes of the TIMER are selected by setting the AUXILIARY
CONTROL REGISTER (ACR). The latches are used to store a 16-bit data
word to load into the counter. Loading a number into the latches does not
affect the count in progress.
After it is set, the countfer yyill begin decrementing at 1 MHz. When the
counter reaches zero, an interrupt flag will be set, and the IRQ will go low.
Depending on how the TIMER is set, either further interrupts will be dis-
abled, or it will automatically load the two latches into the counter and
continue counting. The TIMER can also be set to invert the output signal
on a peripheral pin each time it reaches zero and resets.
The TIMER locations work differently on reading and writing.
WRITING TO THE TIMER:
E: Write into the low order latch. This latch can be loaded into the low
byte of the 1 6-bit counter.
F: Write into the high order latch, write into the high order counter, trans-
fer low order latch into the low order counter, and reset the TIMER T1
interrupt flag. In other words, when this location is set the counter is loaded.
G: Same as E.
H: Write into the high order latch and reset the TIMER T1 interrupt flag.
READ TIMER T1
E: Read the TIMER T1 low order counter and reset the TIMER T1 in-
terrupt flag.
F: Read the TIMER T1 high order counter.
G: Read the TIMER T1 low order latch.
H: Read the TIMER T1 high order latch.
312 MACHINE LANGUAGE FOR COMMODORE MACHINES
TIMER T2
This TIMER operates as an interval timer (in one-shot mode), or as a
counter for counting negative pulses on PORT B pin 6. A bit in the ACR
selects which mode TIMER T2 is in.
WRITING TO TIMER T2
I: Write TIMER T2 low order byte of latch.
J: Write TIMER T2 high order counter byte, transfer low order latch to
low order counter, clear TIMER T2 interrupt flag.
READING TIMER T2
I: Read TIMER T2 low order counter byte, and clear TIMER T2 interrupt
flag.
K: SHIFT REGISTER
A shift register is a register which will rotate itself through the CB2 pin.
The shift register can be loaded with any 8-bit pattern which can be shifted
out through the CB1 pin, or input to the CB1 pin can be shifted into the
shift register and then read. This makes it highly useful for serial to parallel
and parallel to serial conversions.
The shift register is controlled by bits 2-4 of the Auxiliary Control register.
L,M,N,0,P: AUXILIARY CONTROL REGISTER
L: TIMER 1 CONTROL
BIT # 7 6
One-shot mode (output to PB7 disabled)
1 Free running mode (output to PB7 disabled)
1 One-shot mode (output to PB7 enabled)
1 1 Free running mode (output to PB7 enabled)
M: TIMER 2 CONTROL
TIMER 2 has 2 modes. If this bit is 0, TIMER 2 acts as an interval timer
in one-shot mode. If this bit is 1 , TIMER 2 will count a predetermined
number of pulses on pin PB6.
APPENDIX I
313
N: SHIFT REGISTER CONTROL
BIT #
4
3
2
n
n
yj
euicT REGISTER DISABLED
n
1
1
SHIFT IN ^FROM CB1^ UNDER CONTROL OF
TIMER 2
1
SHIFT IN UNDER CONTROL OF SYSTEM CLOCK
PIJLSFS
1
1
SHIFT IN UNDER CONTROL OF EXTERNAL
CLOCK PULSES
1
FREE RUN MODE AT RATE SET BY TIMER 2
1
1
SHIFT OUT UNDER CONTROL OF TIMER 2
1
1
SHIFT OUT UNDER CONTROL OF SYSTEM
CLOCK PULSES
1
1
1
SHIFT OUT UNDER CONTROL OF EXTERNAL
CLOCK PULSES
O: PORT B LATCH ENABLE
As long as this bit is 0, the PORT B register will directly reflect the data
on the pins.
If this bit is set to one, the data present on the input pins of PORT A will
be latched within the chip when the CB1 INTERRUPT FLAG is set. As
long as the CB1 INTERRUPT FLAG is set, the data on the pins can change
without affecting the contents of the PORT B register. Note that the CPU
always reads the register (the latches) rather than the pins.
Input latching can be used with any of the input or output modes available
for CB2.
P: PORT A LATCH ENABLE
As long as this bit is 0, the PORT A register will directly reflect the data
on the pins.
If this bit is set to one, the data present on the input pins of PORT A will
be latched within the chip when the CA1 INTERRUPT FLAG is set. As
long as the CA1 INTERRUPT FLAG is set, the data on the pins can change
without affecting the contents of the PORT A register. Note that the CPU
always reads the register (the latches) rather than the pins.
Input latching can be used with any of the input or output modes available
for CA2.
374
MACHINE LANGUAGE FOR COMMODORE MACHINES
Q,R,S,T THE PERIPHERAL CONTROL REGISTER
0: CB2 CONTROL
O Q O
BIT# 7 6 5
1
1
1 1
1
1 1
1 1
1 1 1
INTERRUPT INPUT MODE:
The CB2 interrupt flag (IFR bit 3) will be set on a negative (high-to-low)
transition on the CB2 input line. The CB2 interrupt bit will be cleared on
a read or write to PORT B.
INDEPENDENT INTERRUPT INPUT MODE:
As above, the CB2 interrupt flag will be set on a negative transition on
the CB2 input line. However, reading or writing to PORT B does not clear
the flag.
INPUT MODE:
The CB2 interrupt flag (IFR bit 3) will be set on a positive (low-to-high)
transition of the CB2 line. The CB2 flag will be cleared on a read or write
of PORT B.
INDEPENDENT INPUT MODE:
As above, the CB2 interrupt flag will be set on a positive transition on the
CB2 line. However, reading or writing PORT B does not affect the flag.
HANDSHAKE OUTPUT MODE:
The CB2 line will be set low on a write to PORT B. It will be reset high
again when there is an active transition on the CB1 line.
PULSE OUTPUT MODE:
The CB2 line is set low for one cycle after a write to PORT B.
DESCRIPTION
Interrupt Input Mode
Independent Interrupt Input Mode
Input Mode
Independent Input Mode
Handshake Output Mode
Pulse Output Mode
Manual Output Mode (CB2 is held LOW)
Manual Output Mode (CB2 is held HIGH)
APPENDIX I
315
MANUAL OUTPUT MODE:
The CB2 line is lield low.
MANUAL OUTPUT MODE:
The CB2 line is held high.
R: CB1 CONTROL
This bit selects the active transition of the input signal applied to the CB1
pin. If this bit is 0, the CB1 interrupt flag will be set on a negative transition
(high-to-low). If this bit is a 1 , the CB 1 interrupt flag will be set on a positive
(low-to-high) transition.
S:CA2 CONTROL
s
s
s
3
2
1
DESCRIPTION
Interrupt Input Mode
1
Independent Interrupt Input Mode
1
Input Mode
1
1
Independent Input Mode
1
Handshake Output Mode
1
1
Pulse Output Mode
1
1
Manual Output Mode (CA2 is held LOW)
1
1
1
Manual Output Mode (GA2 is held HIGH)
INTERRUPT INPUT MODE:
The CA2 interrupt flag (IFR bit 0) will be set on a negative (high-to-low)
transition on the CA2 input line. The CA2 interrupt bit will be cleared on
a read or write to PORT A.
INDEPENDENT INTERRUPT INPUT MODE:
As above, the CA2 interrupt flag will be set on a negative transition on
the CA2 input line. However, reading or writing to PORT A does not clear
the flag.
INPUT MODE:
The CA2 interrupt flag (IFR bit 0) will be set on a positive (low-to-high)
transition of the CA2 line. The GA2 flag will be cleared on a read or write
of PORT A.
376
MACHINE LANGUAGE FOR COMMODORE MACHINES
INDEPENDENT INPUT MODE:
As above, the CA2 interrupt flag will be set on a positive transition on tlie
CA2 line. However, reading or writing PORT A does not affect the flag.
HANDSHAKE OUTPUT MODE:
The CA2 line will be set low on a read or write to PORT A. it will be reset
high again when there is an active transition on the CA1 line.
PULSE OUTPUT MODE:
The CA2 line is set low for one cycle after a read or write to PORT A.
MANUAL OUTPUT MODE:
The CA2 line is held low.
MANUAL OUTPUT MODE:
The CA2 line is held high.
T: CA1 CONTROL
This bit of the PGR selects the active transition of the Input signal applied
to the CA1 input pin. If this bit is 0, the CA1 interrupt flag (Bit) will be set
by a negative transition (high-to-low) on the CA1 pin. If this bit is 1 , the
CA1 interrupt flag will be set by a positive transition (low-to-high).
There are two registers associated with interrupts: The INTERRUPT FLAG
REGISTER (IFR) and the INTERRUPT ENABLE REGISTER (lER). The
IFR has eight bits, each one connected to a register in the 6522. Each bit
in the IFR has an associated bit in the lER. The flag is set when a register
wants to interrupt. However, no interrupt will take place unless the cor-
responding bit in the lER is set.
UVWXYZab: INTERRUPT FLAG REGISTER
When the flag is set, the pin associated with that flag is attempting to
interrupt the 6502. Bit U is not a normal flag. It goes high if both the flag
and the corresponding bit in the INTERRUPT ENABLE REGISTER are
set. It can be cleared only by clearing all the flags in the IFR or disabling
all active interrupts in the lER.
APPENDIX I
317
SET BY
IRQ STATUS
TIMER 1 time-out
CLEARED BY
U
V
Reading TIMER 1 low order
counter and writing TIMER 1
high order latch
W
TIMER 2 time-out
Reading TIMER 2 low order
counter and writing TIMER 2
high order counter
X
Y
Z
CB1 pin active transition
CB2 pin active transition
Completion of 8 shifts
Reading or writing PORT B
Reading or writing PORT B
Reading or writing the shift
register
a
b
CA1 pin active transition
CA2 pin active transition
Reading or writing PORT A
(BBBBBBBB in above chart)
Reading or writing PORT A
(BBBBBBBB in above chart)
cdefghij: INTERRUPT ENABLE REGISTER
c: ENABLE CONTROL
If this bit is a during a write to this register, each 1 in bits 0-6 clears the
corresponding bit in the lER. If this bit is a 1 during this register, each 1
in bits 0-6 will set the corresponding lER bit.
d TIMER 1 time-out enable
e TIMER 2 time-out enable
f CB1 Interrupt enable
g CB2 interrupt enable
h Shift Interrupt enable
i CA1 Interrupt enable
j CA2 Interrupt enable
PORTA
This is similar to BBBBBBBB, except that the handshaking lines (CA1 and
CA2) are unaffected by operations on this port.
378
MACHINE LANGUAGE FOR COMMODORE MACHINES
6526 (CIA) Complex Interface Adaptor
REGISTER MAP
RS3
RS2
RSI
RSO
REG
NAME
PRA
PERIPHERAL DATA REG A
1
1
PRB
PERIPHERAL DATA REG B
1
2
DDRA
DATA DIRECTION REG A
1
1
3
DDRB
DATA DIRECTION REG B
1
4
TALO
TIMER A LOW REGISTER
1
1
5
TA HI
TIMER A HIGH REGISTER
1
1
6
TB LO
TIMER B LOW REGISTER
1
1
1
7
TB HI
TIMER B HIGH REGISTER
8
TOD lOths
10ths OF SECONDS REGISTER
1
9
TOD SEC
SECONDS REGISTER
1
A
TOD MIN
MINUTES REGISTER
1
1
B
TOD HR
HOURS— AM/PM REGISTER
1
C
SDR
SERIAL DATA REGISTER
1
1
D
ICR
INTERRUPT CONTROL REGIS-
TER
1
1
E
CRA
CONTROL REG A
1
1
1
F
CRB
CONTROL REG B
I/O Ports (PRA, PRB, DDRA, DDRB)
Ports A and B each consist of an 8-bit Peripheral Data Register (PR) and
an 8-bit Data Direction Register (DDR). If a bit in the DDR is set to a one,
the corresponding bit in the PR is an output; if a DDR bit is set to a zero,
the corresponding PR bit is defined as an input. On a READ, the PR
reflects the information present on the actual port pins (PA0-PA7, PBO-
PB7) for both input and output bits. Port A and Port B have passive pull-
up devices as well as active pull-ups, providing both CMOS and TTL
compatibility. Both ports have two TTL load drive capability. In addition to
normal I/O operation, PB6 and PB7 also provide timer output functions.
Handshaking
Handshakin g on d ata transfers can be accomplished using the PC output
pin and the FLAG input pin. PC will go low for one cycle following a read
or write of PORT B. This signal can be used to indicate "data ready" at
PORT B or "data accepted" from PORT B. Handshaking on 1 6-bit data
transfers (using both PORT A and PORT B) is possible by always reading
APPENDIX I
319
or writing PORT A first. FLAG is a negative edge sensitive input wiiich
can be used for receiving Vne PC output from anot her 652 6, or as a g eneral
purpose interrupt input. Any negative transition of FLAG will set the FLAG
interrupt bit.
REG
NAME
D7
Ds
D5
D4
D3
D2
D,
Do
PRA
PA7
PAe
PA5
PA4
PA3
PAs
PA,
PAo
1
PRB
PB7
PBe
PB5
PB4
PB3
PB2
PBi
PBo
2
DDRA
DPA7
DPAe
DPA5
DPA4
DPA3
DPA2
DPA,
DPAo
3
DDRB
DPB7
DPBs
DPB5
DPB4
DPB3
DPB2
DPB,
DPBo
Interval Timers (Timer A, Timer B)
Each interval timer consists of a 1 6-bit read-only Timer Counter and a 1 6-
bit write-only Timer Latch. Data written to the timer are latched in the Timer
Latch, while data read from the timer are the present contents of the Time
Counter. The timers can be used independently or linked for extended
operations. The various timer modes allow generation of long time delays,
variable width pulses, pulse trains and variable frequency waveforms.
Utilizing the CNT input, the timers can count external pulses or measure
frequency, pulse width and delay times of external signals. Each timer has
an associated control register, providing independent control of the fol-
lowing functions:
Start/Stop
A control bit allows the time to be started or stopped by the microprocessor
at any time.
PB On/Off:
A control bit allows the timer output to appear on a PORT B output line
(PB6 for TIMER A and PB7 for TIMER B). This function overrides the
DDRB control bit and forces the appropriate PB line to an output.
Toggle/Pulse
A control bit selects the output applied to PORT B. On every timer un-
derflow the output can either toggle or generate a single positive pulse of
one cycle duration. The Toggl e output is set high whenever the timer is
started and is set low by RES.
320
MACHINE LANGUAGE FOR COMMODORE MACHINES
One-Shot/Continuous
A control bit selects either tinner mode. In one-shot mode, the timer will
count down from the latched value to zero, generate an interrupt, reload
the latched value, then stop. In continuous mode, the timer will count from
the latched value to zero, generate an interrupt, reload the latched value
and repeat the procedure continuously.
Force Load
A strobe bit allows the timer latch to be loaded into the timer counter at
any time, whether the timer is running or not.
Input Mode:
Control bits allow selection of the clock used to decrement the timer.
TIMER A can count ^2 clock pulses or external pulses applied to the CNT
pin. TIMER B can count <^2 pulses, external CNT pulses, TIMER A un-
derflow pulses or TIMER A underflow pulses while the CNT pin is held
high.
The timer latch is loaded into the timer on any timer underflow, on a force
load or following a write to the high byte of the prescaler while the timer
is stopped. If the timer is running, a write to the high byte will load the
timer latch, but not reload the counter.
READ (TIMER)
REG NAME
4
TALO
TAL7
TALs
TALs
TAU
TAL3
TAL2
TAL,
TALo
5
TA HI
TAH7
TAHe
TAH5
TAH4
TAH3
TAHs
TAH,
TAHo
6
TB LO
TBL7
TBLe
TBU
TBL4
TBL3
TBL2
TBLi
TBLo
7
TB HI
TBH7
TBHe
TBHs
TBH4
TBH3
TBH2
TBH,
TBHo
WRITE (PRESCALER)
REG NAME
4
TALO
PAL7
PALe
PAL5
PAL4
PAL3
PALs
PAL,
PALo
5
TA HI
PAH7
PAHe
PAH5
PAH4
PAH3
PAH2
PAH,
PAHo
6
TB LO
PB7
PBb
PB5
PB4
PB3
PB2
PB,
PBo
7
TB HI
PBH7
PBHs
PBH5
PBH4
PBH3
PBHa
PBH,
PBHo
APPENDIX I
321
Time of Day Clock (TOD)
The TOD clock is a special purpose timer for real-time applications. TOD
consists of a 24-hour (AM/PM) clock with 1/1 0th second resolution, it is
organized into 4 registers: 10ths of seconds, Seconds, IVlinutes and Hours.
The AM/PM flag is in the MSB of the Hours register for easy bit testing.
Each register reads out in BCD format to simplify conversion for driving
displays, etc. The clock requires an external 60 Hz or 50 Hz (programm-
able) TTL level input on the TOD pin for accurate timekeeping. In addition
to time-keeping, a programmable ALARM is provided for generating an
interrupt at a desired time. The ALARM registers are located at the same
addresses as the corresponding TOD registers. Access to the ALARM is
governed by a Control Register bit. The ALARM is write-only; any read of
a TOD address will read time regardless of the state of the ALARM access
bit.
A specific sequence of events must be followed for proper setting and
reading of TOD. TOD is automatically stopped whenever a write to the
Hours register occurs. The clock will not start again until after a write to
the lOths of seconds register. This assures TOD will always start at the
desired time. Since a carry from one stage to the next can occur at any
time with respect to a read operation, a latching function is included to
keep all Time Of Day information constant during a read sequence. All
four TOD registers latch on a read of Hours and remain latched until after
a read of 1 0ths of seconds. The TOD clock continues to count when the
output registers are latched. If only one register is to be read, there is no
carry problem and the register can be read "on the fly," provided that any
read of Hours is followed by a read of lOths of seconds to disable the
latching.
READ
REG NAME
8
TOD
10THS
Ts
T4
T2
T,
9
TOD
SEC
SH4
SHa
SH,
SLs
SL4
SL2
SL,
A
TOD
MIN
MH4
MHa
MH,
MLg
ML4
ML2
ML,
B
TOD HR
PM
HH
HLa
HU
HL2
HL,
322
MACHINE LANGUAGE FOR COMMODORE MACHINES
WRITE
CRB7 = TOD
CRB7 = 1 ALARM
(SAME FORMAT AS READ)
Serial Port (SDR)
The serial port is a buffered, 8-bit synchronous shift register system. A
control bit selects input or output mode. In input mode, data on the SP
pin is shifted into the shift register on the rising edge of the signal applied
to the CNT pin. After 8 CNT pulses, the data in the shift register is dumped
into the Serial Data Register and an interrupt is generated. In the output
mode, TIMER A is used for the baud rate generator. Data is shifted out
on the SP pin at V2 the underflow rate of TIMER A. The maximum baud
rate possible is <f>2 divided by 4, but the maximum useable baud rate will
be determined by line loading and the speed at which the receiver responds
to input data. Transmission will start following a write to the Serial Data
Register (provided TIMER A is running and in continuous mode). The
clock signal derived from TIMER A appears as an output on the CNT pin.
The data in the Serial Data Register will be loaded into the shift register
then shift out to the SP pin when a CNT pulse occurs. Data shifted out
becomes valid on the falling edge of CNT and remains valid until the next
falling edge. After 8 CNT pulses, an interrupt is generated to indicate more
data can be sent. If the Serial Data Register was loaded with new infor-
mation prior to this interrupt, the new data will automatically be loaded
into the shift register and transmission will continue. If the microprocessor
stays one byte ahead of the shift register, transmission will be continuous.
If no further data is to be transmitted, after the 8th CNT pulse, CNT will
return high and SP will remain at the level of the last data bit transmitted.
SDR data is shifted out MSB first and serial input data should also appear
in this format.
The bidirectional capability of the Serial Port and CNT clock allows many
6526 devices to be connected to a common serial communication bus on
which one 6526 acts as a master, sourcing data and shift clock, while all
other 6526 chips act as slaves. Both CNT and SP outputs are open drain
to allow such a common bus. Protocol for master/slave selection can be
transmitted over the serial bus, or via dedicated handshaking lines.
REG NAME
SDR
s.
S5
S3
S2
s,
So
APPENDIX I
323
Interrupt Control (ICR)
There are five sources of interrupts on the 6526: underflow from TIMER
A, und erflow from TIMER B, TOD ALARM, Serial Port full/empty and
FLAG. A single register provides masking and interrupt information. The
interrupt Control Register consists of a write-only MASK register and a
read-only DATA register. Any interrupt will set the corresponding bit in the
DATA register. Any interrupt which is enabled by the MASK register will
set the IR bit (MSB) of the DATA register and bring the IRQ pin low. In a
multi-chip system, the IR bit can be polled to detect which chip has gen-
erated an interrupt request. The interrupt DATA register is cleared and
the IRQ line returns high following a read of the DATA register. Since each
interrupt sets an interrupt bit regardless of the MASK, and each interrupt
bit can be selectively masked to prevent the generation of a processor
interrupt, it is possible to intermix polled interrupts with true interrupts.
However, polling the IR bit will cause the DATA register to clear, therefore,
it is up to the user to preserve the information contained in the DATA
register if any polled interrupts were present.
The MASK register provides convenient contr ol of ind ividual mask bits.
When writing to the MASK register, if bit 7 (SET/CLEAR) of the data written
is a ZERO, any mask bit written with a one will be cleared, while those
mask bits written with a zero will be unaffected. If bit 7 of the data written
is a ONE, any mask bit written with a one will be set, while those mask
bits written with a zero will be unaffected. In order for an interrupt flag to
set IR and generate an Interrupt Request, the corresponding MASK bit
must be set.
READ (INT DATA)
REG NAME
D
ICR
IR
FLG
SP
ALRM
TB
TA
REG
NAME
WRITE (INT MASK)
D
ICR
S/C
X
X
FLG
SP
ALRM
TB
TA
Control Registers
There are two control registers in the 6526, CRA and CRB. CRA is as-
sociated with TIMER A and ORB is associated with TIMER B. The register
format is as follows:
324
MACHINE LANGUAGE FOR COMMODORE MACHINES
CRA:
Bit Name Function
START 1 = START TIMER A, = STOP TIMER A. This
bit is automatically reset when underflow oc-
curs during one-shot mode.
1 PBON 1 = TIMER A output appears on PB6, = PB6
normal operation.
2 OUTMODE 1 = TOGGLE, = PULSE
3 RUNMODE 1 = ONE-SHOT, = CONTINUOUS
4 LOAD 1 = FORGE LOAD (this is STROBE input, there
is no data storage, bit 4 will always read back
a zero and writing a zero has no effect).
5 INMODE 1 = TIMER A counts positive CNT transitions,
= TIMER A counts <^2 pulses.
6 SPMODE 1 = SERIAL PORT output (CNT sources shift
clock), = SERIAL PORT input (external shift
clock required).
7 TODIN 1 =50 Hz clock required on TOD pin for ac-
curate time, 0=60 Hz clock required on TOD
pin for accurate time.
(Bits CRB0-CRB4 are identical to CRA0-CRA4
for TIMER B with the exception that bit 1 con-
trols the output of TIMER B on PB7).
5,6 INMODE Bits CRB5 and CRB6 select one of four input
modes for TIMER B as:
CRB6 CRB5
TIMER B counts 4>2
pulses.
1 TIMER B counts positive
CNT transitions.
1, TIMER B counts TIMER
A underflow pulses.
1 1 TIMER B counts TIMER
A underflow pulses while
CNT is high.
7 ALARM 1=writing to TOD registers sets ALARM,
= writing to TOD registers sets TOD clock.
APPENDIX I
325
REG
NAME
TOD SP
IN MODE
IN
MODE
LOAD
RUN
MODE
OUT
MODE
PB ON
START
E
CRA
= 60Hz
= INPUT
= 42
1= FORCE
= CONT
0= PULSE
= PBeOFF
= STOP
LOAD
1=50H2
1= OUT-
1=CNT
(STROBE)
1=0.S.
1= TOGGLE
1=PB6 0N
1= START
PUT
REG
NAME
ALARM
IN
MODE
LOAD
RUN
MODE
OUT
MODE
PB ON
START
F
CRB
= TOD
1 =
ALARM
1
1
)
0=62
1=CNT
= TA
1 = CNT-TA
1 = FORCE
LOAD
(STROBE)
0=CONT.
1=0.S.
0= PULSE
1 = TOGGLE
= PB7 0FF
1=PB7 0N
= STOP
1= START
1
All unused register bits are unaffected by a write and are forced to zero
on a read.
COMMODORE SEMICONDUCTOR GROUP reserves the right to
make changes to any products herein to improve reliability, function
or design. COMMODORE SEMICONDUCTOR GRbUP does not
assume any liability arising out of the application or use of any product
or circuit described herein; neither does it convey any license under
its patent rights nor the rights of others.
6566/6567 (VIC-II) Chip Specifications
The 6566/6567 are multi-purpose color video controller devices for use in
both computer video terminals and video game applications. Both devices
contain 47 control registers which are accessed via a standard 8-bit mi-
croprocessor bus (65XX) and will access up to 16k of memory for display
information. The various operating modes and options within each mode
are described.
Character Display Mode
in the character display mode, the 6566/6567 fetches CHARACTER
POINTERS from the VIDEO MATRIX area of memory and translates the
pointers to character dot location addresses in the 2048 byte CHARACTER
BASE area of memory. The video matrix is comprised of 1000 consecutive
locations in memory which each contain an eight-bit character pointer.
The location of the video matrix within memory is defined by VM13-VM10
in register 24($18) which are used as the 4 MSB of the video matrix
326
MACHINE LANGUAGE FOR COMMODORE MACHINES
address. The lower order 1 bits are provided by an internal counter (VC3-
VCO) which steps through the 1000 character locations. Note that the
6566/6567 provides 14 address outputs; therefore, additional system hard-
ware may be required for complete system memory decodes.
CHARACTER POINTER ADDRESS
A13
A12
A11
A10
A09
AOS
A07
A06
AOS
A04
A03
A02
A01
AGO
VM13
VM12
VM11
VM10
VC9
VC8
VC7
VC6
VC5
VC4
VC3
VC2
VC1
VCO
The eight-bit character pointer permits up to 256 different character def-
initions to be available simultaneously. Each character is an 8x8 dot
matrix stored in the character base as eight consecutive bytes. The location
of the character base is defined by CB13-CB11 also in register 24 ($18)
which are used for the 3 most significant bits (MSB) of the character base
address. The 1 1 lower order addresses are formed by the 8-bit character
pointer from the video matrix (D7-D0) which selects a particular character,
and a 3-bit raster counter (RC2-RC0) which selects one of the eight char-
acter bytes. The resulting characters are formatted as 25 rows of 40
characters each. In addition to the 8-bit character pointer, a 4-bit COLOR
NYBBLE is associated with each video matrix location (the video matrix
memory must be 12 bits wide) which defines one of sixteen colors for
each character.
CHARACTER DATA ADDRESS
A13
A12
A11
A10
A09
AOS
A07
A06
AOS
A04
AOS
A02
A01
AOO
CB13
CB12
CB11
D7
D6
D5
D4
D3
D2
D1
DO
RC2
RC1
RCO
Standard Character Mode (MCM = BMM =
ECM = 0)
In the standard character mode, the 8 sequential bytes from the character
base are displayed directly on the 8 lines in each character region. A "0"
bit causes the background #0 color (from register 33 ($21 )) to be displayed
while the color selected by the color nybble (foreground) is displayed for
a "1" bit (see Color Code Table).
APPENDIX I
327
CHARACTER
FUNCTION
BIT
COLOR DISPLAYED
Background
Background #0 color
(register 33 ($21))
Foreground
1
Color selected by 4-bit color nybble
Therefore, each character has a unique color determined by the 4-bit color
nybble (1 of 16) and all characters share the common background color.
Multi-Color Character Mode (MCM = 1,
BMM = ECM = 0)
Multi-color mode provides additional color flexibility allowing up to four
colors within each character but with reduced resolution. The multi-color
mode is selected by setting the MCM bit in register 22 ($16) to "1 ," which
causes the dot data stored in the character base to be interpreted in a
different manner. If the MSB of the color nybble is a "0," the character
will be displayed as described in standard character mode, allowing the
two modes to be inter-mixed (however, only the lower order 8 colors are
available). When the MSB of the color nybble is a "1" (if MCM:MSB(CM)
= 1 ) the character bits are interpreted in the multi-color mode:
FUNCTION
CHARACTER
BIT PAIR
COLOR DISPLAYED
Background
00
Background #0 Color
(register 33 ($21 ))
Background
01
Background #1 Color
(register 34 ($22))
Foreground
10
Background #2 Color
(register 35 ($23))
Foreground
11
Color specified by 3 LSB of color
nybble
Since two bits are required to specify one dot color, the character is now
displayed as a 4 x 8 matrix with each dot twice the horizontal size as in
standard mode. Note, however, that each character region can now con-
tain 4 different colors, two as foreground and two as background (see
MOB priority).
328 MACHINE LANGUAGE FOR COMMODORE MACHINES
Extended Color Mode (ECM = 1, BMM =
MCM = 0)
The extended color mode allows the selection of Individual background
colors for each character region with the normal 8x8 character resolution.
This mode Is selected by setting the ECM bit of register 17 ($11) to "1."
The character dot data Is displayed as in the standard mode (foreground
color determined by the color nybble is displayed for a "1" data bit), but
the 2 MSB of the character pointer are used to select the bacl<ground
color for each character region as follows:
CHAR. POINTER
MS BIT PAIR
BACKGROUND COLOR DISPLAYED FOR BIT
00
Background #0 color (register 33 ($21 ))
01
Background #1 color (register 34 ($22))
10
Background #2 color (register 35 ($23))
11
Background #3 color (register 36 ($24))
Since the two MSB of the character pointers are used for color information,
only 64 different character definitions are available. The 6566/6567 will
force CB10 and CB9 to "0" regardless of the original pointer values, so
that only the first 64 character definitions will be accessed. With extended
color mode each character has one of sixteen individually defined fore-
ground colors and one of the four available background colors.
NOTE: Extended color mode and multi-color mode should not be enabled simulta-
neously^
Bit Map Mode
In bit map mode, the 6566/6567 fetches data from memory in a different
fashion, so that a one-to-one correspondence exists between each dis-
played dot and a memory bit. The bit map mode provides a screen res-
olution of 320H X 200V individually controlled display dots. Bit map mode
is selected by setting the BMM bit in register 17 ($1 1) to a "1 ." The VIDEO
MATRIX Is still accessed as In character mode, but the video matrix data
is no longer Interpreted as character pointers, but rather as color data.
The VIDEO MATRIX COUNTER is then also used as an address to fetch
the dot data for display from the 8000-byte DISPLAY BASE. The display
base address is formed as follows:
APPENDIX I
329
A13
A12
All
A10
A09
AOS
A07
A06
AOS
A04
AOS
A02
A01
AGO
CB13
VC9
VC8
VC7
VC6
VC5
VC4
VC3
VC2
VC1
VCD
RC2
RC1
RCO
VCx denotes the video matrix counter outputs, RCx denotes tlie 3-bit raster
line counter and CB13 is from register 24 ($18). Tlie video matrix counter
steps tlirougli the same 40 locations for eight raster lines, continuing to
the next 40 locations every eighth line, while the raster counter increments
once for each horizontal video line (raster line). This addressing results
in each eight sequential memory locations being formatted as an 8 x 8
dot block on the video display.
Standard Bit Map Mode (BMM = 1,
MCM = 0)
When standard bit map mode is in use, the color information is derived
only from the data stored in the video matrix (the color nybble is disre-
garded). The 8 bits are divided into two 4-bit nybbles which allow two
colors to be independently selected in each 8 x 8 dot block. When a bit
in the display memory is a "0" the color of the output dot is set by the
least significant (lower) nybble (LSN). Similarly, a display memory bit of
"1" selects the output color determined by the MSN (upper nybble).
BIT
DISPLAY COLOR
Lower nybble of video matrix pointer
1
Upper nybble of video matrix pointer
Multi-Color Bit Map Mode (BMM = MCM
= V
Multi-colored bit map mode is selected by setting the MCM bit in register
22 ($16) to a "1" in conjunction with the BMM bit. Multi-color mode uses
the same memory access sequences as standard bit map mode, but
interprets the dot data as follows:
BIT PAIR
DISPLAY COLOR
00
Background #0 color (register 33 ($21 ))
01
Upper nybble of video matrix pointer
10
Lower nybble of video matrix pointer
11
Video matrix color nybble
330 MACHINE LANGUAGE FOR COMMODORE MACHINES
Note that the color nybble (DB1 1 -DBS) IS used for the multi-color bit map
mode, again, as two bits are used to select one dot color, the horizontal
dot size is doubled, resulting in a screen resolution of 160H x 200V.
Utilizing multi-color bit map mode, three independently selected colors can
be displayed in each 8x8 block in addition to the background color.
Movable Object Blocks
The movable object block (MOB) is a special type of character which can
be displayed at any one position on the screen without the block constraints
inherent in character and bit map mode. Up to 8 unique MOBs can be
displayed simultaneously, each defined by 63 bytes in memory which are
displayed as a 24 x 21 dot array (shown below). A number of special
features make MOBs especially suited for video graphics and game ap-
plications.
MOB DISPLAY BLOCK
BYTE
BYTE
BYTE
00
01
02
03
04
05
57
58
59
60
61
62
Enable
Each MOB can be selectively enabled for display by setting its corre-
sponding enable bit (MnE) to "1" in register 21 ($15). If the MnE bit is
"0," no MOB operations will occur involving the disabled MOB.
Position
Each MOB is positioned via its X and Y position register (see register
map) with a resolution of 512 horizontal and 256 vertical positions. The
position of a MOB is determined by the upper-left corner of the array. X
locations 23 to 347 ($17-$157) and Y locations 50 to 249 ($32-$F9) are
visible. Since not all available MOB positions are entirely visible on the
screen, MOBs may be moved smoothly on and off the display screen.
APPENDIX I
331
Color
Each MOB has a separate 4-bit register to determine the IVlOB color. The
two MOB color modes are:
STANDARD MOB (MnMC = 0)
In the standard mode, a "0" bit of MOB data allows any background data
to show through (transparent) and a "1 " bit is displayed as the MOB color
determined by the corresponding MOB Color register.
MULTI-COLOR MOB (MnMC = 1)
Each MOB can be individually selected as a multi-color MOB via MnMC
bits in the MOB Multi-color register 28 ($1C). When the MnMC bit is "1,"
the corresponding MOB is displayed in the multi-color mode. In the multi-
color mode, the MOB data is interpreted in pairs (similar to the other multi-
color modes) as follows:
BIT PAIR
COLOR DISPLAYED
00
Transparent
01
MOB Multi-color #0 (register 37 ($25))
10
MOB Color (registers 39-46 ($27-$2E))
11
MOB Multi-color #1 (register 38 ($26))
Since two bits of data are required for each color, the resolution of the
MOB is reduced to 12x21, with each horizontal dot expanded to twice
standard size so that the overall MOB size does not change. Note that up
to 3 colors can be displayed in each MOB (in addition to transparent) but
that two of the colors are shared among all the MOBs in the multi-color
mode.
Each MOB can be selectively expanded (2 x ) in both the horizontal and
vertical directions. Two registers contain the control bits (MnXE,MnYE)
for the magnification control:
Magnification
REGISTER
FUNCTION
23 ($17)
Horizontal expand MnXE—"1" = expand;
"0" = normal
Vertical expand MnYE—"1"= expand; "0" = normal
29 ($1D)
332
MACHINE LANGUAGE FOR COMMODORE MACHINES
When MOBs are expanded, no increase in resolution is realized. The same
24x21 array (12x21 if multi-colored) is displayed, but the overall MOB
dimension is doubled in the desired direction (the smallest MOB dot may
be up to 4 X standard dot dimension if a MOB is both multi-colored and
expanded).
Priority
The priority of each MOB may be individually controlled with respect to
the other displayed information from character or bit map modes. The
priority of each MOB is set by the corresponding bit (MnDP) of register
27 ($1 B) as follows:
REG BIT
PRIORITY TO CHARACTER OR BIT MAP DATA
Non-transparent MOB data will be displayed (MOB in
front)
1
Non-transparent MOB data wil be displayed only in-
stead of Bkgd #0 or multi-color bit pair 01 (MOB be-
hind)
MOB— DISPLAY DATA PRIORITY
MnDP = 1
MnDP =
MOBn
Foreground
Background
Foreground
MOBn
Background
MOB data bits of "0" ("00" in multi-color mode) are transparent, always
permitting any other information to be displayed.
The MOBs have a fixed priority with respect to each other, with MOB
having the highest priority and MOB 7 the lowest. When MOB data (except
transparent data) of two MOBs are coincident, the data from the lower
number MOB will be displayed. MOB vs. MOB data is prioritized before
priority resolution with character or bit map data.
Collision Detection
Two types of MOB collision (coincidence) are detected, MOB to MOB
collision and MOB to display data collision:
1) A collision between two MOBs occurs when non-transparent output data of
two MOBs are coincident. Coincidence of MOB transparent areas will not
generate a collision. When a collision occurs, the MOB bits (MnM) in the
APPENDIX I
333
MOB-MOB COLLISION register 30 ($1 E) will be set to "1 " for both colliding
MOBs. As a collision between two (or more) MOBs occurs, the MOB-MOB
collision bit for each collided MOB will be set. The collision bits remain set
until a read of the collision register, when all bits are automatically cleared.
MOBs collisions are detected even if positioned off-screen.
2) The second type of collision is a MOB-DATA collision between a MOB and
foreground display data from the character or bit map modes. The MOB-
DATA COLLISION register 31 ($1 F) has a bit (MnD) for each MOB which
is set to "1" when both the MOB and non-background display data are
coincident. Again, the coincidence of only transparent data does not generate
a collision. For special applications, the display data from the 0-1 multicolor
bit pair also does not cause a collision. This feature permits their use as
background display data without interfering with true MOB collisions. A MOB-
DATA collision can occur off-screen in the horizontal direction if actual display
data has been scrolled to an off-screen position (see scrolling). The MOB-
DATA COLLISION register also automatically clears when read.
The collision interrupt latches are set whenever the first bit of either register
is set to "1 ." Once any collision bit within a register is set high, subsequent
collisions will not set the interrupt latch until that collision register has been
cleared to all "Os" by a read.
MOB Memory Access
The data for each MOB is stored in 63 consecutive bytes of memory. Each
block of MOB data is defined by a MOB pointer, located at the end of the
VIDEO MATRIX. Only 1000 bytes of the video matrix are used in the
normal display modes, allowing the video matrix locations 1016-1 023 (VM
base-i-$3F8 to VM base + $3FF) to be used for MOB pointers 0-7, re-
spectively. The eight-bit MOB pointer from the video matrix together with
the six bits from the MOB byte counter (to address 63 bytes) define the
entire 14-bit address field:
A13
A12
All
A10
A09
AOS
A07
A06
AOS
A04
A03
A02
A01
AGO
MP7
MP6
MPS
MP4
MP3
MP2
MP1
MPO
MCS
MC4
MCS
MC2
MCI
MCO
Where MPx are the MOB pointer bits from the video matrix and MCx are
the internally generated MOB counter bits. The MOB pointers are read
from the video matrix at the end of every raster line. When the Y position
register of a MOB matches the current raster line count, the actual fetches
of MOB data begin. Internal counters automatically step through the 63
bytes of MOB data, displaying three bytes on each raster line.
334 MACHINE LANGUAGE FOR COMMODORE MACHINES
Other Features
Screen Blanking
The display screen may be blanked by setting the DEN bit in register 1 7
($11) to a "0." When the screen is blanked, the entire screen will be filled
with the exterior color as in register 32 ($20). When blanking is active,
only transparent (Phase 1) memory accesses are required, permitting full
processor utilization of the system bus. MOB data, however, will be ac-
cessed if the MOBs are not also disabled. The DEN bit must be set to "1 "
for normal video display.
Row/Column Select
The normal display consists of 25 rows of 40 characters (or character
regions) per row. For special display purposes, the display window may
be reduced to 24 rows and 38 characters. There is no change in the format
of the displayed information, except that characters (bits) adjacent to the
exterior border area will now be covered by the border. The select bits
operate as follows:
NUMBER OF
NUMBER OF
RSEL
ROWS
CSEL
COLUMNS
24 rows
38 columns
1
25 rows
1
40 columns
The RSEL bit is in register 17 ($11) and the CSEL bit is in register 22
($16). For standard display the larger display window is normally used,
while the smaller display window is normally used In conjunction with
scrolling.
Scrolling
The display data may be scrolled up to one entire character space in both
the horizontal and vertical direction. When used in conjunction with the
smaller display window (above), scrolling can be used to create a smooth
panning motion of display data while updating the system memory only
when a new character row (or column) is required. Scrolling is also used
to center a fixed display within the display window.
BITS
X2,X1,X0
Y2,Y1 ,Y0
REGISTER
22 ($16)
17 ($11)
FUNCTION
Horizontal Position
Vertical Position
APPENDIX I
335
Light Pen
The light pen input latches the current screen position into a pair of reg-
isters (LPX.LPY) on a low-going edge. The X position register 19 ($13)
will contain the 8 MSB of the X position at the time of transition. Since the
X position is defined by a 512-state counter (9 bits) resolution to 2 hori-
zontal dots is provided. Similarly, the Y position is latched to its register
20 ($14) but here 8 bits provide single raster resolution within the visible
display. The light pen latch may be triggered only once per frame, and
subsequent triggers within the same frame will have no effect. Therefore,
you must take several samples before turning the light pen to the screen
(3 or more samples, average), depending upon the characteristics of your
light pen.
Raster Register
The raster register is a dual-function register. A read of the raster register
18 ($12) returns the lower 8 bits of the current raster position (the MSB-
RC8 is located in register 1 7 ($1 1 )). The raster register can be interrogated
to implement display changes outside the visible area to prevent display
flicker. The visible display window is from raster 51 through raster 251
($033-$0FB). A write to the raster bits (including RC8) is latched for use
in an internal raster compare. When the current raster matches the written
value, the raster interrupt latch is set.
Interrupt Register
The interrupt register shows the status of the four sources of interrupt. An
interrupt latch in register 25 ($19) is set to "1" when an interrupt source
has generated an interrupt request. The four sources of interrupt are:
LATCH
ENABLE
BIT
BIT
WHEN SET
IRST
ERST
Set when (raster count) = (stored raster
count)
IMDC
EMDC
Set by MOB-DATA collision register (first
collision only)
IMMC
EMMC
Set by MOB-MOB collision register (first
collision only)
ILP
ELP
Set by negative transition of LP input (once
per frame)
IRQ
Set high by latch set and enabled (invert of
IRQ/ output)
336
MACHINE LANGUAGE FOR COMMODORE MACHINES
To enable an interrupt request to set the IRQ/ output to "0," the corre-
sponding interrupt enable bit in register 26 ($1 A) must be set to "1 ." Once
an interrupt latch has been set, the latch may be cleared only by writing
a "1" to the desired latch in the interrupt register. This feature allows
selective handling of video interrupts without software required to "re-
member" active interrupts.
Dynamic Ram Refresh
A dynamic ram refresh controller is built into the 6566/6567 devices. Five
8-bit row addresses are refreshed every raster line. This rate guarantees
a maximum delay of 2.02 ms between the refresh of any single row address
in a 128 refresh scheme. (The maximum delay is 3.66 ms in a 256 address
refresh scheme.) This refresh is totally transparent to the system, since
the refresh occurs during Phase 1 of the system clock. The 6567 generates
both RAS/ and CAS/ which are normally connected directly to the dynamic
rams. RAS/ and CAS/ are generated for every Phase 2 and every video
data access (including refresh) so that external clock generation is not
required.
Reset
The reset bit (RES) in register 22 ($16) is not used for normal operation.
Therefore it should be set to "0" when initializing the video chip. When
set to a "1 ," the entire operation of the video chip is suspended, including
video outputs and sync, memory refresh, and system bus access.
Theory of Operation
System Interface
The 6566/6567 video controller devices interact with the system data bus
in a special way. A 65XX system requires the system buses only during
the Phase 2 (clock high) portion of the cycle. The 6566/6567 devices take
advantage of this feature by normally accessing system memory during
the Phase 1 (clock low) portion of the clock cycle. Therefore, operations
such as character data fetches and memory refresh are totally transparent
to the processor and do not reduce the processor throughput. The video
chips provide the interface control signals required to maintain this bus
sharing.
The video devices provide the signal AEC (address enable control) which
is used to disable the processor address bus drivers allowing the video
device to access the address bus. AEC is active low which permits direct
APPENDIX I
337
connection to the AEC input of the 65XX family. The AEC signal is normally
activated during Phase 1 so that processor operation is not affected. Be-
cause of this bus "sharing," all memory accesses must be completed in
Vz cycle. Since the video chips provide a 1-MHz clock (which must be
used as system Phase 2), a memory cycle is 500 ns including address
setup, data access and, data setup to the reading device.
Certain operations of the 6566/6567 require data at a faster rate than
available by reading only during the Phase 1 time; specifically, the access
of character pointers from the video matrix and the fetch of MOB data.
Therefore, the processor must be disabled and the data accessed during
the Phase 2 clock. This is accomplished via the BA (bus available) signal.
The BA line is normally high but is brought low during Phase 1 to indicate
that the video chip will require a Phase 2 data access. Three Phase-2
times are allowed after BA low for the processor to complete any current
memory accesses. On the fourth Phase 2 after BA low, the AEC signal
will remain low during Phase 2 as the video chip fetches data. The BA
line is normally connected to the RDY input of a 65XX processor. The
character pointer fetches occur every eighth raster line during the display
window and require 40 consecutive Phase 2 accesses to fetch the video
matrix pointers. The MOB data fetches require 4 memory accesses as
follows:
PHASE
DATA
CONDITION
1
MOB Pointer
Every raster
2
MOB Byte 1
Each raster while MOB is displayed
1
MOB Byte 2
Each raster while MOB is displayed
2
MOB Byte 3
Each raster while MOB is displayed
The MOB pointers are fetched every other Phase 1 at the end of each
raster line. As required, the additional cycles are used for MOB data
fetches. Again, all necessary bus control is provided by the 6566/6567
devices.
Memory Interface
The two versions of the video interface chip, 6566 and 6567, differ in
address output configurations. The 6566 has thirteen fully decoded ad-
dresses for direct connection to the system address bus. The 6567 has
multiplexed addresses for direct connection to 64K dynamic RAMs. The
least significant address bits, A06-A00, are present on A06-A00 while RAS/
is brought low, while the most significant bits, A13-A08, are present on
A05-A00 while CAS/ is brought low. The pins A11-A07 on the 6567 are
338
MACHINE LANGUAGE FOR COMMODORE MACHINES
z
g
H
Q.
E
o
w
ui
a
o
m
Q
m
Q
CM
ID
Q
n
m
a
ffi
Q
ffi
Q
(O
m
o
1^
m
Q
(0
(0
UJ
oc
Q
O
<
ccccccccccccccccg
.2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 .2 ~
■55 '55 '55 '55 'w 'w w '55 w w w 'w "w '« "w "m J5 m
0000000000000000°*=
a.a.a.a.Q.Q.a.Q.aLQ.Q.Q.Q.Q.Q.Q.9-(»
x>x>-x>x>-x>-x>-x>-x>-x«
ooT-T-cMCMcocorj-"<tu)U5totor«~r>-.'5
OOOOOOOOOOOOOOOOW
> -
— X
'o c c ffl
£: 0} a> c
L. a. a. UJ
oc □ □ S
2? o
^ E S .'^ §■
ffl tc ^ O) t
O g g
S S £ m
0000000000000000
x>-x>x>x>-x>-x>-x>-x>-
ooT--i-cjc\jcoco^'*inm<D<Dr^r>-
00 o LU
Xoox^-lJJO^
S CC _l _l S S
I gg£
X?X>X>X>X>X>X>X>Sr,^X?
ooi--i-cMCJcoco'sr-*tnintotor>-r>-i->-0£Q~'-X'^tIlS^S
CO CM LLI CM O ^
CM
CM
CM
CM
CM
CM
CM
CM
CM
CM
CM
CM
CM
CM
CM
CO
X
>-
X
>-
X
>
X
X
>
X
>-
X
>-
X
>-
X
T—
CM
CM
CO
CO
■t
in
10
CO
CO
1^
CM
CO
CO
CO
CO
CO
CO
CO
CO
CO
CO
CO
CO
CO
CO
CO
CO
00
X
>-
X
>
X
>-
X
>-
X
>-
X
>-
X
>
X
>
X
CM
CM
CO
CO
•<t
'sr
in
in
CO
CO
CO
:s
i
i
IS
_1 r^. (Y, -1 LU CO
Luco5>:iuLU>-T-_
coOoIqIswscqci,
a:£ri]i]2o5od
UJ
■t
00
X
>
X
?
X
X
>-
X
>
X
>-
X
CM
CM
CO
CO
m
in
(O
CO
■si-
i
i
m
_^ in -St-
7<X>
UJ
UJ O
>- n
S S S S Q OC
^ ^ ^ I I
SSS> I I
in
in
in
If)
in
in
in
in
in
in
in
10
U1
in
in
in
00
X
>-
X
>-
X
>
X
X
>
X
>-
X
>-
X
>-
X
CM
CM
CO
CO
m
in
CO
CO
in
i
i
IS
S
S
S
S
CO
CO
CO
CO
CO
CO
(O
CO
CO
CO
CO
CO
CO
CO
CO
CO
00
X
>
X
>-
X
>-
X
>
X
>
X
>-
X
>-
X
>■
X
i
CM
CM
CO
CO
in
in
CO
CO
CO
S
S
S
s
S
s
S
S
S
S
S
S
in
CO
CD in ,,, ty
X >- UI CO >- r:
^ £ in UJ w 2
-I -I S QC S >
I I
1^ <D IM
X >-
UJ OC
i I
UJ CM
11
I I
l>-
1^
1^
1^
1^
1^
00
X
>-
X
>
X
>
X
>-
X
>
X
>-
X
>-
X
>-
X
i
CM
CM
CO
CO
in
in
CO
CO
1^
r«.
S
s
1
s
s
S
S
s
s
S
S
S
s
S
S
CO l>*
O O
cc oc
CO 1^ ,,,
X >- LU
Q. 0. N
_i _i S
UJ CO
I s > £
OT-CMC0'SflO<0h~00O)<0QOQUJU.O'^CMC0'*in<OI^C0O)<
OOOOOOOOOOOOOOOOi-'^i--i--i-i-i--i-i-i--'-
Oi-CMco-st-incoh*ooo»o-i-CMco'*in<or«-ooo50t-cMco'^inco
OOOOOOOOOOT--I--I-T-1-1-1--I-T-T-CMCMCMCMCMCMCM
APPENDIX I
339
^ 0)
< .9
9 ^
m CO
O O
c
g
cc O
S-m
9 O
>< 5
CD CO
O O
c
o
'jm
o
O
<
O
I
CO
O
o i-
o o o o
o o o o
O O OO
O 1- CM CO
-a T3 -a
O) G) O) C7>
^ ^ jk: ^
CO CO CQ CQ
O
IS
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
o
O
O
O
O
O
O
O
O
o
CM
CO
in
(£>
1^
CQ
CO
CQ
CQ
CQ
CO
CQ
CO
o
o
O
O
o
O
O
O
2
CL O
o o
S Q
o o
0- O LU
Q 5 X
S Q
Q.
o
LU
Q
IS
x:
Q
CM
CM
CM
CM
CM
Q.
o
LU
O
X
Q
CO
CO
CO
CO
CO
o
O
o
O
O
O
O
O
T—
CM
CO
CQ
CQ
CQ
;r: o o o
O O T- CM CO
CM
CO
o
o
o
o
O
o
o
o
o
i
O
O
O
O
o
O
O
O
o
CM
CO
in
CO
r«-
i
:e
:s
IS
O
o
T—
O
o
O
O
O
O
i
o
CM
CO
■>t
in
(O
CM
CM
CM
CM
CM
CM
CM
CM
CM
i
o
O
O
o
o
o
o
o
o
CM
CO
in
CO
i
CO
CO
CO
CO
CO
CO
CO
CO
CO
i
o
O
O
o
O
O
O
o
o
CM
CO
■<t
in
(O
i
IS
Q. O LU
Q 2 X S Q
■<t ■<*■
;i s s IS s
I I I I I I I I I I I I I I I
as
£
CO
0. g LU ^
Q S X 2 Q
in in in in in .
S S S S S I
0.
O
LU
Q
X
Q
CO
(O
(O
CO
(O
I I I I I I I I I I I I I I
I I
I I I I I I I I I
o
(U
c
c
8
0. O UJ
Q IS X S Q
r>. rs. fs. r>. ,
s s s s s I
I I I I I I I I I I I I I I
COOQLULLO'.-CMCO'>i-LOCONOOC3)<CQOQLU
■I-1-T-T-1-CMCMCMCMCMCMCVICMCMCMCMCMCMCMCM
r r ^ »^ »^ » ^ >^ f t\ fn t f\ t f\ t f\ ff\
\TT try WT yy yy yy yy yy yy yy yy yy
h-ooo)Oi-cMco^incDr^cooso-i-CMcO'*incD
CMCMCMCOCOCOCOCOCOCOCOCOCO'd-^'*'*'*-*-*
(0
CO
-D
<
lii
H
o
340
MACHINE LANGUAGE FOR COMMODORE MACHINES
COLOR CODES
D4
Do
Ul
UU
ucv
Hex*
BLACK
1
1
1
WHITE
1
2
2
RED
1
1
3
3
CYAN
1
4
4
PURPLE
1
1
5
5
GREEN
1
1
6
6
BLUE
1
1
1
7
7
YELLOW
1
8
8
ORANGE
1
9
9
BROWN
1
A
10
LTRED
1
1
B
11
DARK GRAY
1
C
12
MED GRAY
1
1
D
13
LT GREEN
1
1
E
14
LT BLUE
1
1
1
F
15
LT GRAY
static address outputs to allow direct connection of these bits to a con-
ventional 1 6K (2K X 8) ROM. (The lower order addresses require external
latching.)
6581 Sound Interface Device (SID) Chip
Specifications
Concept
The 6581 Sound Interface Device (SID) is a single-chip, 3-voice electronic
music synthesizer/sound effects generator compatible with the 65XX and
similar microprocessor families. SID provides wide-range, high-resolution
control of pitch (frequency), tone color (harmonic content), and dynamics
(volume). Specialized control circuitry minimizes software overhead, fa-
cilitating use in arcade/home video games and low-cost musical instru-
ments.
Features
• 3 TONE OSCILLATORS
Range: 0-4 kHz
APPENDIX I
341
• 4 WAVEFORMS PER OSCILLATOR
Triangle, Sawtooth,
Variable Pulse, Noise
• 3 AMPLITUDE MODULATORS
Range: 48 dB
• 3 ENVELOPE GENERATORS
Exponential response
Attack Rate: 2 ms— 8 s
Decay Rate: 6 ms— 24 s
Sustain Level: — peal< volume
Release Rate: 6 ms — 24 s
• OSCILLATOR SYNCHRONIZATION
• RING MODULATION
Description
The 6581 consists of three synthesizer "voices" which can be used in-
dependently or in conjunction with each other (or external audio sources)
to create complex sounds. Each voice consists of a Tone Osciilator/Wave-
form Generator, an Envelope Generator and an Amplitude Modulator. The
Tone Oscillator controls the pitch of the voice over a wide range. The
Oscillator produces four waveforms at the selected frequency, with the
unique harmonic content of each waveform providing simple control of
tone color. The volume dynamics of the oscillator are controlled by the
Amplitude Modulator under the direction of the Envelope Generator. When
triggered, the Envelope Generator creates an amplitude envelope with
programmable rates of increasing and decreasing volume. In addition to
the three voices, a programmable Filter is provided for generating complex,
dynamic tone colors via subtractive synthesis.
SIS allows the microprocessor to read the changing output of the third
Oscillator and third Envelope Generator. These outputs can be used as
a source of modulation information for creating vibrator, frequency/filter
sweeps and similar effects. The third oscillator can also act as a random
number generator for games. Two A/D converters are provided for inter-
facing SID with potentiometers. These can be used for "paddles" in a
game environment or as front panel controls in a music synthesizer. SID
can process external audio signals, allowing multiple SID chips to be daisy-
chained or mixed in complex polyphonic systems.
342
MACHINE LANGUAGE FOR COMMODORE MACHINES
SID Control Registers
There are 29 eight-bit registers in SID which control the generation of
sound. These registers are either WRITE-only or READ-only and are listed
below in Table 1 .
SID Register Description
Voice 1
FREQ LO/FREQ HI (Registers 00,01)
Together these registers form a 1 6-bit number which linearly controls the
frequency of Oscillator 1 . The frequency is determined by the following
equation:
Fout = (Fn X Fcik/1 677721 6) Hz
Where Fn is the 1 6-bit number in the Frequency registers and Fdk is the
system clock applied to the 4)2 input (pin 6). For a standard 1 .0-MHz clock,
the frequency is given by:
Fout = (Fn X 0.059604645) Hz
A complete table of values for generating 8 octaves of the equally tempered
musical scale with concert A (440 Hz) tuning is provided in Appendix E.
It should be noted that the frequency resolution of SID is sufficient for any
tuning scale and allows sweeping from note to note (portamento) with no
discernable frequency steps.
PW LO/PW HI (Registers 02,03)
Together these registers form a 12-bit number (bits 4-7 of PW HI are not
used) which linearly controls the Pulse Width (duty cycle) of the Pulse
waveform on Oscillator 1 . The pulse width is determined by the following
equation:
PWout = (PWn/40.95)%
Where PWn is the 12-bit number in the Pulse Width registers.
The pulse width resolution allows the width to be smoothly swept with no
discernable stepping. Note that the Pulse waveform on Oscillator 1 must
be selected in order for the Pulse Width registers to have any audible
APPENDIX I
343
>-.>.>-.>■.
a £
EC P
9 9
C DC
9 9 9 9
" UJ ^ ^
b
DC
i
9
UJ
t
DC
DC
3
DC
9 9
ii
9 I
11 ii I iili
« 3 I „
I iiii
il
if
if
i
t
i
f
1
if
i
i
i
i
i£'
■T
i
i
ii
i
1
tT
if
i
i
i
i
iT
i
1
1
iH!
iF
i
i
I?
i
1
1
it
if
t
1
1
1
1
S 5 3 S S S S
^OOOOi- '-i-
4POOOOO oo
^ooooo oo
if
if
1
t
1
i
i
iT
if
i
i
i
if
iT
i
i
ii
i
i
if
if
i
i
1
f
S
I?
i
i
f
i
if
iF
i
i
i
if
iT
t
f
i
it
iT
i
1
1
i
g S S g S 2 B
if
if
1°
i
1
i
f
uT
if
i
i
1
f
i
if
ir
i
ii
f
if
i
i
1
i
if
iT
i
f
f
if
iT
i
i
if
if
f
f
f
iir
if
i
1
1
f
g ° - 5! 5 5
o j: 5! n
, « » j; o a g
344 MACHINE LANGUAGE FOR COMMODORE MACHINES
^ h ^ h
z z z z
9 9 9 9
^ ^ ^ t
h h t ^
z z z z
9 9 9 9
a a 6 Q
^1
O — U. LU
-1 I ia Q
o o ui Q
ql a. cc s
o
Q
z
i
RLT1
3
§
2
RLT2 i
s
FILT3 1
i?
§
1
RLTEX 1
J?
§
1
Ui
IE
0.
-1
1
CO
lU
IT
m
1
CM
m
m
tc
0.
X
1
o
2
JS
m
(E
30R= 1
6 *• O .0
I 5 s § i
' £ 0. a lu
i
0.
§
S
i
i
6
lU
i
i
d
i
i
S
iff
■i
i
S
liT
i
i
6
m
)?
0.
i
S
to
UI
i
i
6
in <D N CO
a> < OD o
o 1- o
o o o «-
n ol S3 S
^ n ^
APPENDIX I
345
effect. A value of or 4095 ($FFF) in the Pulse Width registers will produce
a constant DC output, while a value of 2048 ($800) will produce a square
wave.
CONTROL REGISTER (Register 04)
This register contains eight control bits which select various options on
Oscillator 1 .
Gate (Bit 0): The GATE bit controls the Envelope Generator for Voice 1 .
When this bit is set to a one, the Envelope Generator is Gated (triggered)
and the ATTACK/DECAY/SUSTAIN cycle is initiated. When the bit is reset
to a zero, the RELEASE cycle begins. The Envelope Generator controls
the amplitude of Oscillator 1 appearing at the audio output, therefore, the
GATE bit must be set (along with suitable envelope parameters) for the
selected output of Oscillator 1 to be audible. A detailed discussion of the
Envelope Generator can be found at the end of this Appendix.
SYNC (Bit 1): The SYNC bit, when set to a one, synchronizes the fun-
damental frequency of Oscillator 1 with the fundamental frequency of
Oscillator 3, producing "Hard Sync" effects.
Varying the frequency of Oscillator 1 with respect to Oscillator 3 produces
a wide range of complex harmonic structures from Voice 1 at the frequency
of Oscillator 3. In order for sync to occur, Oscillator 3 must be set to some
frequency other than zero but preferably lower than the frequency of
Oscillator 1 . No other parameters of Voice 3 have any effect on sync.
RING MOD (Bit 2): The RING MOD bit, when set to a one, replaces the
Triangle waveform output of Oscillator 1 with a "Ring Modulated" com-
bination of Oscillators 1 and 3. Varying the frequency of Oscillator 1 with
respect to Oscillator 3 produces a wide range of non-harmonic overtone
structures for creating bell or gong sounds and for special effects. In order
for ring modulation to be audible, the Triangle waveform of Oscillator 1
must be selected and Oscillator 3 must be set to some frequency other
than zero. No other parameters of Voice 3 have any effect on ring mod-
ulation.
TEST (Bit 3): The TEST bit, when set to a one, resets and locl<s Oscillator 1
at zero until the TEST bit is cleared. The Noise waveform output of Oscillator 1
is also reset and the Pulse waveform output is held at a DC level. Normally
this bit is used for testing purposes, however, it can be used to synchronize
Oscillator 1 to externa! events, allowing the generation of highly complex
waveforms under real-time software control.
346 MACHINE LANGUAGE FOR COMMODORE MACHINES
(Bit 4): When set to a one, the Triangle waveform output of Oscillator 1
is selected. The Triangle wavefornn is low in harmonics and has a mellow,
flute-like quality.
(Bit 5): When set to a one, the Pulse waveform output of Oscillator 1 is
selected. The Sawtooth waveform is rich in even and odd harmonics and
has a bright, brassy quality.
(Bit 6): When set to a one, the Pulse waveform of Oscillator 1 is selected.
The harmonic content of this waveform can be adjusted by the Pulse
Width registers, producing tone qualities ranging from a bright, hollow
square wave to a nasal, reedy pulse. Sweeping the pulse width in real-
time produces a dynamic "phasing" effect which adds a sense of motion
to the sound. Rapidly jumping between different pulse widths can produce
interesting harmonic sequences.
NOISE (Bit 7): When set to a one, the Noise output waveform of Oscillator 1
is selected. This output is a random signal which changes at the frequency
of Oscillator 1 . The sound quality can be varied from a low rumbling to
hissing white noise via the Oscillator 1 Frequency registers. Noise is useful
in creating explosions, gunshots, jet engines, wind, surf and other un-
pitched sounds, as well as snare drums and cymbals. Sweeping the os-
cillator frequency with Noise selected produces a dramatic rushing effect.
One of the output waveforms must be selected for Oscillator 1 to be au-
dible, however, it is NOT necessary to de-select waveforms to silence the
output of Voice 1 . The amplitude of Voice 1 at the final output is a function
of the Envelope Generator only.
NOTE: The oscillator output waveforms are NOT additive. If more
than one output waveform is selected simultaneously, the result will
be a logical ANDing of the waveforms. Although this technique can
be used to generate additional waveforms beyond the four listed
above, it must be used with care. If any other waveform is selected
while Noise is on, the Noise output can "lock up." If this occurs, the
Noise output will remain silent until reset by the TEST bit or by
bringing RES (pin 5) low.
ATTACK/DECAY (Register 05)
Bits 4-7 of this register (ATK0-ATK3) select 1 of 16 ATTACK rates for
the Voice 1 Envelope Generator. The ATTACK rate determines how rapidly
the output of Voice 1 rises from zero to peak amplitude when the Envelope
Generator is Gated. The 16 ATTACK rates are listed in Table 2.
APPENDIX I
347
Bits 0-3 (DCYO— DCY3) select 1 of 16 DECAY rates for the Envelope
Generator. The DECAY cycle follows the ATTACK cycle and the DECAY
rate determines how rapidly the output falls from the peak amplitude to
the selected SUSTAIN level. The 16 DECAY rates are listed in Table 2.
SUSTAIN/RELEASE (Register 06)
Bits 4-7 of this register (STNO— STN3) select 1 of 16 SUSTAIN levels
for the Envelope Generator. The SUSTAIN cycle follows the DECAY cycle
and the output of Voice 1 will remain at the selected SUSTAIN amplitude
as long as the Gate bit remains set. The SUSTAIN levels range from zero
Table 2. Envelope Rates
VALUE
ATTACK RATE
DECAY/RELEASE
RATE
DEC (HEX)
(Time/Cycle)
(Time/Cycle)
(0)
2 ms
6 ms
1 (1)
8 ms
24 ms
2 (2)
16 ms
48 ms
3 (3)
24 ms
72 ms
4 (4)
38 ms
114 ms
5 (5)
56 ms
168 ms
6 (6)
68 ms
204 ms
7 (7)
80 ms
240 ms
8 (8)
100 ms
300 ms
9 (9)
250 ms
750 ms
10 (A)
500 ms
1.5 s
11 (B)
800 ms
2.4 s
12 (C)
1 s
3s
13 (D)
3 s
9s
14 (E)
5s
15s
15 (F)
8s
24 s
NOTE: Envelope rates are based on a 1 .0-MHz <t)2 clock. For other
4)2 frequencies, multiply the given rate by 1 MHz/<})2. The rates refer
to the amount of time per cycle. For example, given an ATTACK
value of 2, the ATTACK cycle would take 16 ms to rise from zero to
peak amplitude. The DECAY/RELEASE rates refer to the amount of
time these cycles would take to fall from peak amplitude to zero.
348 MACHINE LANGUAGE FOR COMMODORE MACHINES
to peak amplitude in 16 linear steps, with a SUSTAIN value of selecting
zero amplitude and a SUSTAIN value of 15 ($F) selecting the peak am-
plitude. A SUSTAIN value of 8 would cause Voice 1 to SUSTAIN at an
amplitude one-half the peak amplitude reached by the ATTACK cycle.
Bits 0-3 (RLS0-RLS3) select 1 of 16 RELEASE rates for the Envelope
Generator. The RELEASE cycle follows the SUSTAIN cycle when the
Gate bit is reset to zero. At this time, the output of Voice 1 will fall from
the SUSTAIN amplitude to zero amplitude at the selected RELEASE rate.
The 16 RELEASE rates are identical to the DECAY rates.
NOTE: The cycling of the Envelope Generator can be altered at any
point via the Gate bit. The Envelope Generator can be Gated and
Released without restriction. For example, if the Gate bit is reset
before the envelope has finished the ATTACK cycle, the RELEASE
cycle will immediately begin, starting from whatever amplitude had
been reached. If the envelope is then gated again (before the RE-
LEASE cycle has reached zero amplitude), another ATTACK cycle
will begin, starting from whatever amplitude had been reached. This
technique can be used to generate complex amplitude envelopes
via real;time software control.
Voice 2
Registers 07-$0D control Voice 2 and are functionally identical to registers
00-06 with these exceptions:
1) When selected, SYNC synchronizes Oscillator 2 with Oscillator 1.
2) When selected, RING MOD replaces the Triangle output of Oscillator 2 with
the ring modulated combination of Oscillators 2 and 1 .
Voice 3
Registers $0E-$14 control Voice 3 and are functionally identical to reg-
isters 00-06 with these exceptions:
1) When selected, SYNC synchronizes Oscillator 3 with Oscillator 2.
2) When selected, RING MOD replaces the Triangle output of Oscillator 3 with
the ring modulated combination of Oscillators 3 and 2.
Typical operation of a voice consists of selecting the desired parameters:
frequency, waveform, effects (SYNC, RING MOD) and envelope rates,
then gating the voice whenever the sound is desired. The sound can be
sustained for any length of time and terminated by clearing the Gate bit.
APPENDIX I
349
Each voice can be used separately, with independent parameters and
gating, or in unison to create a single, powerful voice. When used in unison,
a slight detuning of each oscillator or tuning to musical intervals creates
a rich, animated sound.
Filter
FC LO/FC HI (Registers $15,$16)
Together these registers form an 11 -bit number (bits 3-7 of FC LO are
not used) which linearly controls the Cutoff (or Center) Frequency of the
programmable Filter. The approximate Cutoff Frequency ranges from 30
Hz to 12 KHz.
RES/FILT (Register $17)
Bits 4-7 of this register (RES0-RES3) control the resonance of the filter.
Resonance is a peaking effect which emphasizes frequency components
at the Cutoff Frequency of the Filter, causing a sharper sound. There are
16 resonance settings ranging linearly from no resonance (0) to maximum
resonance (15 or $F). Bits 0-3 determine which signals will be routed
through the Filter:
FiLT 1 (Bit 0): When set to a zero. Voice 1 appears directly at the audio
output and the Filter has no effect on it. When set to a one, Voice 1 will
be processed through the Filter and the harmonic content of Voice 1 will
be altered according to the selected Filter parameters.
FILT 2 (Bit 1): Same as bit for Voice 2.
FILT 3 (Bit 2): Same as bit for Voice 3.
FILTEX (Bit 3): Same as bit for External audio input (pin 26).
MODE VOL (Register $18)
Bits 4-7 of this register select various Filter mode and output options:
LP (Bit 4): When set to a one, the Low-Pass output of the Filter is selected
and sent to the audio output. For a given Filter input signal, all frequency
components below the Filter Cutoff Frequency are passed unaltered, while
all frequency components above the Cutoff are attenuated at a rate of 12
dB/Octave. The Low-Pass mode produces full-bodied sounds.
BP (Bit 5): Same as bit 4 for the Bandpass output. All frequency com-
ponents above and below the Cutoff are attenuated at a rate of 6 dB/
Octave. The Bandpass mode produces thin, open sounds.
350 MACHINE LANGUAGE FOR COMMODORE MACHINES
HP (Bit 6): Same as bit 4 for tlie High-Pass output. All frequency com-
ponents above tfie Cutoff are passed unaltered, wliile all frequency com-
ponents below thie Cutoff are attenuated at a rate of 12 dB/Octave. The
High-Pass mode produces tinny, buzzy sounds.
3 OFF (Bit 7): When set to a one, the output of voice 3 is disconnected
from the direct audio path. Setting Voice 3 to bypass the Filter (FILT 3 =
0) and setting 3 OFF to a one prevents Voice 3 from reaching the audio
output. This allows Voice 3 to be used for modulation purposes without
any undesirable output.
NOTE: The Filter output modes ARE additive and multiple Filter
modes may be selected simultaneously. For example, both LP and
HP modes can be selected to produce a Notch (or Band Reject)
Filter response. In order for the Filter to have any audible effect, at
least one Filter output must be selected and at least one Voice must
be routed through the Filter. The Filter is, perhaps, the most important
element in SID as it allows the generation of complex tone colors
via subtractive synthesis (the Filter is used to eliminate specific fre-
quency components from a harmonically rich input signal). The best
results are achieved by varying the Cutoff Frequency in real-time.
Bits 0-3 (VOL0-VOL3) select 1 of 16 overall Volume levels for the final
composite audio output. The output volume levels range from no output
(0) to maximum volume (15 or $F) in 16 linear steps. This control can be
used as a static volume control for balancing levels in multi-chip systems
or for creating dynamic volume effects, such as Tremolo. Some Volume
level other than zero must be selected in order for SID to produce any
sound.
Miscellaneous
POTX (Register $19)
This register allows the microprocessor to read the position of the poten-
tiometer tied to POTX (pin 24), with values ranging from at minimum
resistance, to 255 ($FF) at maximum resistance. The value is always valid
and is updated every 512 (1)2 clock cycles. See the Pin Description section
for information on pot and capacitor values.
POTY (Register $1A)
Same as POTX for the pot tied to POTY (pin 23).
APPENDIX I
351
OSC 3/RANDOM (Register $1B)
This register allows the microprocessor to read the upper 8 output bits of
Oscillator 3. The character of the numbers generated is directly related to
the waveform selected. If the Sawtooth waveform of Oscillator 3 is se-
lected, this register will present a series of numbers incrementing from
to 255 ($FF) at a rate determined by the frequency of Oscillator 3. If the
Triangle waveform is selected, the output will increment from up to 255,
then decrement down to 0. If the Pulse waveform is selected, the output
will jump between and 255. Selecting the Noise waveform will produce
a series of random numbers, therefore, this register can be used as a
random number generator for games. There are numerous timing and
sequencing applications for the OSC 3 register, however, the chief function
is probably that of a modulation generator. The numbers generated by
this register can be added, via software, to the Oscillator or Filter Fre-
quency registers or the Pulse Width registers in real-time. Many dynamic
effects can be generated in this manner. Siren-like sounds can be created
by adding the OSC 3 Sawtooth output to the frequency control of another
oscillator. Synthesizer "Sample and Hold" effects can be produced by
adding the OSC 3 Noise output to the Filter Frequency control registers.
Vibrato can be produced by setting Oscillator 3 to a frequency around
7 Hz and adding the OSC 3 Triangle output (with proper scaling) to the
Frequency control of another oscillator. An unlimited range of effects are
available by altering the frequency of Oscillator 3 and scaling the OSC 3
output. Normally, when Oscillator 3 is used for modulation, the audio output
of Voice 3 should be eliminated (3 OFF = 1).
ENV 3 (Register $1C)
Same as OSC 3, but this register allows the microprocessor to read the
output of the Voice 3 Envelope Generator. This output can be added to
the Filter Frequency to produce harmonic envelopes, WAH-WAH, and
similar effects. "Phaser" sounds can be created by adding this output to
the frequency control registers of an oscillator. The Voices Envelope
Generator must be Gated in order to produce any output from this register.
The OSC 3 register, however, always reflects the changing output of the
oscillator and is not affected in any way by the Envelope Generator.
352 MACHINE LANGUAGE FOR COMMODORE MACHINES
6525 Tri-Port Interface
Concept
The 6525 TRI-PORT Interface (TPI) is designed to simplify the imple-
mentation of complex I/O operations in microcomputer systems. It com-
bines two dedicated 8-bit I/O ports with a third 8-bit port programmable
for either normal I/O operations or priority interrupt/handshal<ing control.
Depending on the mode selected, the 6525 can provide 24 individually
programmable I/O lines or 16 I/O lines, 2 handshake lines and 5 priority
interrupt inputs.
6525 Addressing
6525 REGISTERS/(Direct Addressing)
*000
RO
PRA— Port Register A
001
R1
PRB— Port Register B
010
R2
PRC— Port Register C
oil
R3
DDRA — Data Direction Register A
100
R4
DDRB— Data Direction Register B
101
R5
DDRC — Data Direction Register C/interrupt Mask Register
110
R6
CR— Control Register
111
R7
AIR — Active Interrupt Register
•NOTE: RS2, RSI, RSO respectively
6525 Control Registers
CR
AIR
DDRC
When MC = 1
PRC
When MC = 1
CBi
CBo
CAi
CAo
IE4
IE3
IP
MC
A4
A3
A2
Ai
Ao
M4
M3
Mg
Mi
Mo
CB
CA
IRQ
I4
I3
I2
I1
■o
CA, CB Functional Description
The CA, CB lines are outputs used in the same fashion as the CA2 and
CB2 output of the 6520.
APPENDIX I
353
CA Output Modes
CAi CAo
MODE
DESCRIPTION
"Handshake"
on Read
Pulse Output
Manual
Output
Manual
Output
CA is set high on an active transition of the I3
interrupt input signal and set low by a micropro-
cessor "Read A Data" operation. This allows
positive control of data transfers from the pe-
ripheral device to the microprocessor.
CA goes low for IMS after a "Read A Data" op-
eration. This pulse can be used to signal the
peripheral device that data was taken.
CA set low.
CA set high.
CB Output Modes
CB-| CBq
MODE
DESCRIPTION
1
"Handshake"
on Write
Pulse Output
Manual
Output
Manual
Output
CB is set low on microprocessor "Write B Data"
operation and is set high by an active transition
of the I4 interrupt input signal. This allows positive
control of data transfers from the microprocessor
to the peripheral device.
CB goes low for IMS after a microprocessor "Write
B Data" operation. This can be used to signal
the peripheral device that data is available.
CB set low.
CB set high.
INTERRUPT MASK REGISTER DESCRIPTION
When the Interrupt Mode is selected (MC = 1), the Data Direction Register
for Port C (DDRC) is used to enable or disable a corresponding interrupt
input. For example: If Mq = then Iq is disabled and any Iq interrupt latched
in the interrupt latch register will not be transferred to the AIR and will not
cause IRQ to .go low. The interrupt latch can be cleared by writing a zero
to the appropriate I bit in PRC.
354
MACHINE LANGUAGE FOR COMMODORE MACHINES
PORT REGISTER C DESCRIPTION
Port Register C (PRC) can operate in two modes. Tiie mode is controlled
by bit MC in register CR. When MC = 0, PRC is a standard I/O port,
operating identically to PRA & PRB. If MC = 1 , then port register C is
used for handshal<ing and priority interrupt input and output.
PRC When MC = 0:
z
PC7
PCs
PCs
PC4
PC3
PC2
PCi
PCo
PRC When MC = 1:
CB
CA
IRQ
I4
I3
I2
I1
lo
INTERRUPT EDGE CONTROL
Bits IE4 and IE3 in the control register (CR) are used to determine the
active edge which will be recognized by the interrupt latch.
If IE4 (IE3) = then I4 (I3) latch will be set on a negative transition of I4
(I3) input.
If IE4 (IE3) = 1 then I4 (I3) latch will be set on a positive transition of the
U (I3) input.
All other interrupt latches (I2. 11, lo) are set on a negative transition of the
corresponding interrupt input.
I4
I3
I2
I1
_o
Interrupt Latch Register
Clears on Read of AIR Using Following
Equation
ILR ^ ILR @ AIR
A4
A3
A2
Ai
Ao
IP
Active Interrupt Register
Clears on Write to AIR
Interrupt Priority Select
IP = No Priority
IP = 1 Interrupts Prioritized
APPENDIX I
355
FUNCTIONAL DESCRIPTION
1 . IP = No Priority
All interrupt information latched into interrupt latch register (ILR) is im-
mediately transferred into active interrupt register (AIR) and IRQ is pulled
low. Upon read of interrupt the IRQ is reset high and the appropriate bit(s)
of the interrupt latch register is cleared by exclusive OR-ing. The ILR with
AIR (ILR0AIR). After the appropriate interrupt request has been serviced
a Write to the AIR will clear it and initiate a new interrupt sequence if any
interrupts were received during previous interrupt sen/icing. In this non-
prioritized mode it is possible for two or more interrupts to occur simul-
taneously and be transferred to the AIR. If this occurs it is a software effort
to recognize this and act accordingly.
2. IP = 1 Interrupts Prioritized
In this mode the Interrupt Inputs are prioritized in the following order I4 >
I3 > I2 > I1 > lo
In this mode only one bit of the AIR can be set at any one time. If an
interrupt occurs it is latched into the interrupt latch register, the IRQ line
is pulled low and the appropriate bit of the AIR is set. To understand fully
the operation of the priority interrupts it is easiest to consider the following
examples.
A. The first case is the simplest. A single interrupt occurs and the pro-
cessor can service it completely before another interrupt request is
received.
1 . Interrupt 1 1 is received.
2. Bit_li is set high in Interrupt Latch Register.
3. IRQ is pulled low.
4. Ai is set high.
5. Processor recognizes IRQ and reads AIR to determine which in-
terrupt occurred.
6. Bit I1 is reset and IRQ is reset to high.
7. Processor Services Interrupt and signals completion of Service
routine by writing to AIR.
8. Ai is reset low and interrupt sequence is complete.
B. The second case occurs when an interrupt has been received and a
higher priority interrupt occurs. (See Note)
1 . Interrupt I1 is received.
2. Bit I 1 is set high on the Interrupt Latch Register.
3. IRQ is pulled low and Ai is set high.
356 MACHINE LANGUAGE FOR COMMODORE MACHINES
4. Processor recognizes IRQ and reads AIR to determine which
interrupt occurred.
5. Bit li is reset and IRQ is reset high.
6. Processor begins servicing li interrupt and the I2 interrupt is re-
ceived.
7. A2 is set, Ai is reset low and IRQ is pulled low.
8. Processor has not yet completed servicing I, interrupt so this
routi ne w ill be automatically stacked in 6500 stack queue when
new IRQ for I2 of interrupt is received.
9. Processor reads AIR to determine I2 interrupt occurrence and bit
I2 of interrupt latch is reset.
10. Processor services I2 interrupt, clears A2 by writing AIR and re-
turns from interrupt. Returning from interrupt causes 650X pro-
cessor to resume servicing I1 interrupt.
11. Upon clearing A2 bit in AIR, the A, bit will not be restored to a
one. Internal circuitry will prevent a lower priority interrupt from
interrupting the resumed I1.
C. The third case occurs when an interrupt has been received and a
lower priority interrupt occurs.
1. Interrupt I, is received and latched.
2. IRQ is pulled low and A-, is set high.
3. Processor recognizes IRQ and reads AIR to determine that 1^ in-
terrupt occurred.
4. Processor logic servicing 1^ interrupt during which Iq interrupt oc-
curs and is latched.
5. Upon completion of I1 interrupt routine the processor writes AIR
to clear A, to signal 6525 that interrupt servi ce is complete.
6. Latch lo interrupt is transferred to AIR and IRQ is pulled low to
begin new interrupt sequence.
NOTE: It was indicated that the 6525 will maintain Priority Interrupt
information from previously serviced interrupts.
This is achieved by the use of an Interrupt Stack. This stack is pushed
whenever a read of AIR occurs and is pulled whenever a write to
AIR occurs. It is therefore important not to perform any extraneous
reads or writes to AIR since this will cause extra and unwanted stack
operations to occur.
The only time a read of AIR should occur is to respond to an interrupt
request.
The only time a write of AIR should occur is to signal the 6525 that
the interrupt service is complete.
Disk User's
Guide
The optional disk holds programs supplementary to the book. The pro-
grams are as follows:
SUPEEMONl (for original ROM PET computers)
SUPERMONE (for upgrade ROM PET/CBM computers)
SUPERM0N4 (for 4.0 PET/CBIVI computers)
SUPERMON . V (for VIC-20 computers)
SOPERMONt^ (for Commodore 64 computers)
SUPERMON INST(instructions, BASIC)
SUPERMON + PET (for upgrade and 4.0 PET/CBM)
SUPERMON + VIC (for VIC-20 computers)
SUPERMON + fc<(for Commodore 64 computers)
SUPERMON + INST (instructions, Basic)
UNICOPYt^ (for Commodore 64)
UNICOPY INST (instructions, BASIC)
UNICOPY LIST (BASIC, all machines)
]UNICOPY asSY (data file for UNICOPY LIST)
COPY -ALL (for PET/CBM)
COPY - &LL . I2A (for Commodore 64)
CROSS REF (for PET/CBIVI)
CROSS REF hA (for Commodore 64)
CROSS REF 12fl (for Commodore 128)
FACTORS (for PET/CBM)
357
358 MACHINE LANGUAGE FOR COMMODORE MACHINES
FACTORS Vt< (for VIC-20, Commodore 64, and Plus-4)
FACTORS 12fl (for Commodore 128)
PENTOMINOS INST (instructions)
PENTOMINOS (BASIC, all machines)
PENTOMINOS PET (for PET/CBM)
PENTOMINOS VLA (for VIC-20, Commodore 64, and Plus-4)
PENTOMINOS lEfl (for Commodore 128)
PENTOMINOS B15fl (boot for 8128 system)
+ PENT01Sfl (program for 81 28)
+ XFER (transfer sequence for 81 28)
STRING THING (8ASIC, for PET/CBM)
STRING THING 7hA (BASIC, for VIC-20, Commodore 64)
STRING THING 15fl (for Commodore 128)
ISAMPLE FILE (for use with STRING THING)
These programs are public domain, and may be obtained from user groups.
They are available here for user convenience.
The following notes may be useful in using or studying the programs.
SDPERMONl (for original ROM PET computers)
SUPERMONS (for upgrade ROM PET/CBM computers)
SOPERMON^ (for 4.0 PET/CBM computers)
SUPERMON . V (for VIC-20 computers)
SOPERMONt^ (for Commodore 64 computers)
SUPERMON INST (instructions, BASIC)
Supermen 2 and 4 are "extensions" to the built-in MLM of the respective
machines. The other Supermon versions are complete monitors. These
are the "original" Supermon programs.
Remember that the programs on disk are "monitor generators," that is,
they build the monitor for you. After the monitor has been built, you should
remove the builder program so that you don't end up with two copies. In
other words, after RON type .X to return to BASIC, NEW to scrap the
builder, and then SYS^orSYSflto return to the monitor whenever de-
sired.
The monitor is always built near the top of memory. Its entry address can
be determined by checking the TOM (top-of-memory) pointer. Monitors
are complex, but feel free to ask the monitor to disassemble itself for your
information.
After Supermon is placed, you may load BASIC programs and use the
computer normally. Supermon will remain until you shut off the power.
APPENDIX d
359
SUPERMON + PET (for upgrade and 4.0 PET/CBM)
SDPERMON + VIC (for VIC-20 computers)
SliPERMON + (for Commodore 64 computers)
SUPERMON + INST (instructions, Basic)
A revised version of SDPERMON; tlie commands closely correspond to
those of the built-in monitors of the Plus-4 and Commodore 128. Contains
a number of convenience features not found in the original SUPER-
MON.
UNICOPYE,/;
A utility for copying files from one disk to another, on a single drive; or
copying from one disk to cassette tape. The program is written entirely in
machine language, apart from the SYS that starts it up.
Information is copied from the selected files into RAM memory. When the
output phase begins, the data is then written to disk or tape.
ONICOPY INST
A BASIC program explaining how to use ONICOPYt^.
UNICOPY LIST
JUNICOPY ftSSY
An assembly listing of program UNICOPY. Because UNICOPY is written
entirely in machine language, a number of tasks are performed in the
program that are often more conveniently done in BASIC. For example,
files are opened and closed by machine language. This makes the program
listing particularly interesting for students of these techniques.
Assembly listings have a somewhat different appearance from the machine
language programs this book has dealt with. The most visible difference
is in the use of symbolic addresses. If there is any confusion, concentrate
on the machine language half of the listing; that will clarify what's going
on. Program UNICOPY LIST allows output to the screen or to a Com-
modore printer.
For cassette tape output, direct calls to the ROM routines are made; that's
usually not good practice, but there's little choice here.
The program is written in machine language so that the BASIC ROM can
be flippped out, allowing for more memory space in which to copy pro-
grams.
COPY -ALL (for PET/CBM)
COPY - ALL . I2A (for Commodore 64)
360
MACHINE LANGUAGE FOR COMMODORE MACHINES
A utility for copying files from one disk drive to another. You will find two
SYS commands in the BASIC part of the program: one to get the directory,
and the other to do the actual copying.
Information is copied from the selected file into a BASIC string that has
been set aside for the purpose. A similar technique may be found in the
simpler STRING THING.
CROSS REF (for PET/CBM)
CROSS REF t< (for Commodore 64)
CROSS REF lEfl (for Commodore 128)
This program prepares a cross-reference listing for any selected BASIC
program on disk. It cross-references both line numbers and variables. It's
a good way to document a BASIC program.
The program uses two table lookup techniques that may be confusing to
the beginning machine language program reader. First, it classifies all
characters received from BASIC in terms of "type "; this is done with a
table of 256 elements, one for each possible character. Second, it uses
a "state transition table" to record the nature of the job in progress; for
example, after meeting a GOSUB "token," it will expect to receive a line
number.
The second SYS in the BASIC program is used to print the line numbers
of the cross-reference. It employs an efficient binary-to-decimal conversion
technique, which uses decimal mode.
FaCTORS (for PET/CBM)
FACTORS Vt< (for VIC-20, Commodore 64, and Plus-4)
FfiCTORSiaa (for Commodore 128)
This program finds factors of numbers up to nineteen digits long. This
shows a powerful feature of machine language as opposed to BASIC: the
size of numbers is not limited by the language.
The program contains a number of useful techniques worth studying. First,
it allows a decimal input of any number up to 19 digits (a 64-bit or 8-byte
binary number). Second, to find factors it performs division with remainder.
Finally, to print results, It must convert binary-to-decimal, using the same
decimal mode technique as in CROSS REF.
The program does not try all divisors. After trying a few initial values (2,
3, and 5), it switches to a "30-counter" technique, trying only multiples of
30 plus 1,7, 11, 17, 19,23, and 29.
The machine language program Is relocated by BASIC so that it starts at
hexadecimal (in the CI 28 version, IDDD) regardless of where it
APPENDIX J
361
was originally loaded. This was originally done to allow for the VIC-20's
variable start-of-BASIC, which rambles according to the amount of extra
memory fitted. It turns out to be useful for study to have the program in a
fixed location; so the PET/CI\^B version was also set up in this way.
Students wishing to disassemble FACTORS will find the following infor-
mation useful:
vaRIABLES (see note for C-128):
$034 R — number of times a factor divides evenly
$□ 34 R— "equals" or "asterisk" character for formatting
$U3AB — zero suppression flag
$D3i^C— 30— counter
$0350 to $0357— value under analysis
$035fl to $035F— value work area
$03bD to $03t7— "base" value for 30-counter
$03fcC to $ 03 7 H— division work area, including:
$D3EiC to $ 03 tF— remainder
$0370 to $0377— quotient
C-128 note: The above locations are sensitive in the C128; the above
variables have been relocated to page B. Thus, instead of $034 R given
above, address $OB<<=i will be used.
PROGRAM (see note for C128):
$13 00 : Main routine, including:
$1300 : Start, clear work area
$131D : Get number digits from user
$1331 : Handle bad input
$133 A : Begin factoring; check non-zero
$1350 : Try divisors 2, 3, and 5
$ 1 3 b 5 : Try higher divisors
$13AE: Print remaining value.
$ 1 3 B A : Prompt subroutine
$13C4: Input and analyze digit
$ 1 < B : Multiply-by-two subroutine
$ 1 1 5 : Division subroutine
$147 A : Try a divisor (short)
$1<7D : Try a divisor (long)
$1465: Check if remainder zero
$ 1 4 5 : Log factor if found
$14AE : Check if more to do
$14B<=I: Print value subroutine
362
MACHINE LANGUAGE FOR COMMODORE MACHINES
$1<D0: Print factor subroutine
$15D^ : Clear output area
$150F : Convert to decimal and print
$1535: Print a digit with zero suppression
$15t5 : 30-count values: 1,7,11, etc.
CI 28 note: Basic is located at quite a high address in this machine; the
start address of the program has been moved up to $100 □ to allow for
this. The above table is correct if the extra offset is allowed; thus $1^15
above becomes $1E15 in the CI 28.
Even at machine language speeds, this program can tal<e a long time to
analyze large factors and prime numbers. The RDN/STOP key is active
to allow the user to stop the run.
PENTOMINOS INST (Instructions)
PENTOMINOS (BASIC, all machines)
PENTOMINOS PET (for PET/CBM)
PENTOMINOS Vt^ (for VIC-20, Commodore 64, and Plus-4)
PENTOMINOS lEfl (for Commodore 128)
PENTOMINOS BlEfl (boot for B128 system)
+ PENT015fl (program for B128)
+ XFE R (transfer sequence for 81 28)
This is a puzzle solving problem. Pieces are fitted into a selected rectan-
gular shape "visibly"— In other words, they may be seen on the screen
as they are tried.
The machine language programs follow the logic of the BASIC program
precisely. The "shape tables" have been rearranged for greater machine
language convenience (each piece Is reached by indexing; the index range
of to 255 dictates the piece being selected and Its rotation).
The machine language program uses no indirect addressing and no sub-
routines. That is not necessarily good practice; it is largely a result of
writing the program logic to exactly match the BASIC program.
This program makes use of tables, and is worth studying for that reason.
It is also useful to examine the close relationship between the BASIC
program and its machine language equivalent, especially starting at line
2000 In BASIC.
As with FACTORS, the machine language program is relocated by BASIC
so that it starts at hexadecimal 15kD (with tables starting at $1EFA)
regardless of where it was originally loaded. Again, this is necessary for
the VIC-20 and proves to be convenient for study purposes on all ma-
chines — except the B-128 version, where this relocation does not happen.
APPENDIX J
363
Students wishing to disassemble PENTOMINOS will find the following
information useful:
VARIABLES (see C128 note):
$DB3C— piece number, BASIC variable P
$D33D to $D33E— variables W1 and W2, board size
$D33F — P1, number of pieces placed
$□340 to $D3AB—U{..) log of pieces placed
$D3<C to $0357— T(..) rotation of piece
$035fl to $D35C— X(..) location of piece
$D35D to $D3bl— Y(..) location of piece
$a3tEto$D37 □— tables to place a piece
$037F to $ 03 qc— board "edge" table
$D3RD to $D3Dfl— B(...) the board.
C128 note: The above locations are sensitive in the C128; the above
variables have been relocated to page B. Thus, instead of $D3bE given
above, address $DBt5 will be used.
PROGRAM (see C128 note):
$15tD: Start, BASIC line 1070
$1SAA: Clear screen, BASIC line 1120
$ 1 5 A S : Clear variables, set up
$15CC : Find space, BASIC line 2010
SltOD : Get new piece, BASIC line 2030
Sltnq : Try piece, BASIC line 2060
$ltflt : Put piece in, BASIC line 2120
$lbEQ : Print "Solution", BASIC line 2170
$1701 : Undraw piece, BASIC line 2190
$ 1 7 AB : Rotate piece, BASIC line 2260
$17BC : Give up on piece, BASIC line 2280
$17C1 : Look for new piece, BASIC line 2300
CI 28 note: Basic is located at quite a high address in this machine; the
start address of the program has been moved up to SlFtD to allow for
this. The above table is correct if the extra offset Is allowed; thus $lbDD
above becomes SEDDD in the C128.
The B128 version does not align to the above addresses. It is written to
illustrate the "boot" loading system needed for that computer. Programs
whose names begin with a + symbol are loaded by the bootstrap program;
do not try to load them directly.
364 MACHINE LANGUAGE FOR COMMODORE MACHINES
STRING THING (BASIC, for PET/CBM)
STRING THING Vt< (BASIC, for VIC-20, Commodore 64, Plus-4)
STRING THING lEfl (Commodore 128)
ISAMPLE FILE
A simple machine language program , POKEable directly from BASIC, to
substitute for an INPUT# statement.
INPaT# has several limitations that sometimes make it awkward for use
with files:
• No more than 80 characters may be read.
• The comma or colon character will break up input.
• Leading spaces will disappear.
STRING THING reads everything up to the next RETURN or end of
file. It is pure BASIC, but POKEs machine language into the cassette
buffer area. It finds the first variable and uses it as an input buffer.
The 128 machine language program is brief and makes good study ma-
terial. Since the program is in bank but the variable table is in bank 1 ,
it is necessary to call special Kernal routine INDFET ( $FF7^ ) to get
the information. Later, when the program wishes to place a character into
the string (which also resides in bank 1), it must call special Kernal routine
INDSTA ( $FF77 ) to get it there. The manner in which the calls are set
up is instructive.
Glossary
The numbers in parentheses indicate the chapter in which the word or,
phrase is first used.
Absolute address: (5) An address that can indicate any location in
memory.
Accumulator: (3) The A register; the register used for arithmetic.
Address bus: (1) A bus that signals which part of memory is wanted
for the next memory operation.
Address mode: (5) The manner in which an instruction reaches in-
formation within memory.
Address: (1) The identity of a specific location within memory.
Algorithm: (1) A method or procedure to perform a computing tasl<.
Arithmetic shift or rotate: (4) A shift or rotate that usually preserves
the sign of a number.
Assembler: (2) A program that assembles or changes source code
into object code.
Assembly: (1 ) The process of changing source code into object code.
Assembly code: (1) Also called source code. A program written in a
somewhat human-readable form. Must be translated ("assembled") before
use.
365
366 MACHINE LANGUAGE FOR COMMODORE MACHINES
Assembly language: (1) The set of instructions, or language, in which
a source program must be written before assembly.
Binary: (1) Something that has two possible states; a number based
on digits, each of which has two possible states.
Bit: (1) A binary digit; the smallest element of information within a
computer.
Bootstrap: (6) A program that starts up another program.
Breakpoint: (8) A location where the program will stop so as to allow
checking for errors.
Bug: (8) An error within a program.
Bus: (1) A collection of wires connecting many devices together.
Byte: (1) Eight bits of information grouped together; the normal mea-
sure of computer storage.
Calling point: (2) The program location from which a subroutine is
called into play; the subroutine will return to the calling point when finished.
Channel: (8) A path connecting the computer to one of its external
devices.
Comment: (8) A program element which does not cause the computer
to do anything, used as advice to the human program reader.
Commutative: (3) A mathematical operation that works both ways,
e.g., 3 + 4 gives the same result as 4 + 3.
Control bus: (1) A bus that signals timing and direction of data flow
to the various connected devices.
Data bus: (1) A bus used to transfer data between memory and the
microprocessor.
Debugging: (8) Testing a program to uncover possible errors.
Decimal: (1) A number system based on a system of ten digits; the
"normal" numbering system used by humans.
Decrement: (2) To make smaller by a value of one.
Descriptor: (6) A three-byte set of data giving a string's length and
its location.
Disassembler: (2) A program that changes object code into assembly
code to allow inspection of a program.
Disassemble: (2) To change object code into assembly code. Similar
to a LIST in BASIC.
Dynamic string: (6) A string that must be placed into memory after
being received or calculated.
Effective address: (2) The address used by the processor to handle
data when executing an instruction. It may differ from the instruction ad-
dress (or "operand") because of indexing or indirect addressing.
Event flag: (7) A flag that signals that some event has happened.
Execute: (1) To perform an instruction.
GLOSSARY
367
File: (8) A collection of data stored on some external device.
Flag: (3) An on/off indicator that signals some condition.
Floating accumulator: (7) A group of memory iocations used by BASIC
to perform calculations on a number.
Garbage collection: (6) A BASIC process in which active strings are
gathered together and inactive strings are discarded. On some computers
this can be quite time consuming.
Increment: (2) To make larger by a value of one.
Index: (2) To change an address by adding the contents of an index
register.
Index register: (2) The X or Y registers, which may be used for chang-
ing effective addresses.
Indirect address: (5) An addressing scheme whereby the instruction
contains the location of the actual address to be used; an address of an
address.
Instruction: (1 ) An element of a program that tells the processor what
to do.
Interrupt: (1) An event that causes the processor to leave its normal
program so that some other program takes control, usually temporarily.
Interrupt enable register: (7) A location within an lA chip that deter-
mines whether or not a selected event will cause an interrupt.
Interrupt flag: (7) A signal within the lA indicating that a certain event
has requested that an interrupt take place.
Interrupt flag register: (7) A location within the lA where interrupt
events can be detected and turned off if desired.
Interrupt source: (7) The particular event that caused an interrupt.
Since many things can do this, it's usually necessary to identify the specific
source of the interrupt.
Kernal: (2) Commodore's operating system.
Label, symbolic address: (8) A name identifying a memory location.
Latch: (7) A flag that "locks in."
Load: (1) To bring information from memory into the processor. A
load operation is a copying activity; the information still remains in memory.
Logical file number: (8) The identity of a file as used by the program-
mer.
Logical operator: (3) An operation that affects individual bits within a
byte: AND, ORA, and EOR.
Logical shift or rotate: (4) A shift that does not preserve the sign of
a signed number.
Machine code: (1) Instructions written in machine language.
Machine language: (1) The set of commands that allow you to give
instructions to the processor.
368 MACHINE LANGUAGE FOR COMMODORE MACHINES
Machine language monitor: (1 ) A program that allows communication
with the computer in a manner convenient for machine language pro-
gramming.
Memory: (1 ) The storage used by a computer; every location is iden-
tified by an address.
Memory mapped: (1) Circuits that can be reached by the use of a
niemoiy address, even though they are not used for storage or memory
purposes.
Memory page: (5) A set of 256 locations in memory, all of whose
addresses have the same "high byte."
Microcomputer: (1) A computer system containing a microprocessor,
memory, and input/output circuits. A computer built using microchips.
Microprocessor: (1) The central logic of a microcomputer, containing
logic and arithmetic. A processor built on a microchip.
Monitor: (1) A program that allows the user to communicate with the
computer. Alternatively, a video screen device.
Non-maskable interrupt, NMI: (7) A type of interrupt that cannot be
disabled.
Non-symbolic assembler: (2) An assembler in which actual addresses
must be used.
Object code: (1) The machine language program that will run in the
computer.
Octothorpe: (2) Sometimes called a numbers sign, a pounds sign, a
hash mark. The "#" symbol.
Operand: (1) The part of an instruction following the op code that
usually signals where in memory the operation is to take place.
Operating system: (1) A set of programs with a computer that takes
care of general work such as input/output, timing, and so on.
Operation code, op code: (1) The part of an instruction that says
what to do.
Overflow: (3) Condition caused by an arithmetic operation generating
a result that is too big to fit in the space provided.
Pointer: (6) An address held in memory, usually in two bytes.
Processor status word, status register: (3) A processor register that
holds status flags.
Pull: (7) To take something from the stack.
Push: (7) To put something on the stack.
Random access memory, RAM: (1 ) The part of a computer's memory
where information can be stored and recalled.
Read: (1) To obtain information from a device.
Read only memory, ROM: (1 ) The part of a computer's memory where
fixed information has been stored. New information cannot be stored in a
ROM; it is preprogrammed.
GLOSSARY
369
Register: (1) Location within a processor where information can be
held temporarily.
Screen editing: (1) The ability to change the screen of a computer
and cause a corresponding change in memory.
Screen memory: (2) The part of a computer holding the information
displayed on the screen. Changing screen memory will change the screen;
reading screen memory will reveal what is on the screen.
Selected: (1) A chip or device that has been signaled to participate
in a data transfer. If the chip or device has not been selected, it will ignore
data operations.
Seif-modifying: (7) A type of program that changes itself as it runs.
Rare, and not always considered good programming practice.
Signed number: (3) A number that holds a value that may be either
positive or negative.
Source code: (1) Instructions written in assembly language; usually,
the first code written by the programmer before performing an assembly.
Stacl<: (7) A temporary, or "scratch pad," set of memory locations.
Status register, processor status word: (3) Within the processor, a
register that holds status flags.
Store: (1) To transfer information from the processor to memory. The
store operation is a copying activity: the information still remains in the
processor.
Subroutine: (2) A set of instructions that can be called up by another
program.
Symbolic address, label: (7) A name identifying a memory location.
Symbolic assembler: (2) An assembler in which symbolic addresses
may be used. This is more powerful than a non-symbolic assembler.
Testable flag: (3) A flag that can be tested by means of a conditional
branch instruction.
Two's complement: (3) A method of representing negative numbers.
With single byte numbers, - 1 would be represented by $FF.
Unsigned number: (3) A number that cannot have a negative value.
Write: (1) To send information to a device.
Zero page: (5) The lowest 256 locations in memory. Locations whose
addresses begin with hexadecimal $00. . .
Index
A, X, and Y data registers, 9, 11,
46, 47, 142
Absolute addressing, 148
Absolute indexed mode, 77-78
Absolute indirect, 149
Absolute mode, 75-76
Accumulator addressing, 148
Accumulator mode, 74
ADC, Add memory to accumulator
with carry, 149
Addition, 58-60
Address, defined, 3
Address bus, 3-5
Addressing modes, 72-89,
148-149
Algorithms:
decimal to hexadecimal, 7
hexadecimal to decimal, 7
AND, "AND" memory with
accumulator, 121, 149
ASCII, 25, 50, 249-250
ASL, Shift left one bit (memory or
accumulator), 61-62, 149
Assemblers:
nonsymbolic, 27
symbolic, 143-144
BASIC:
breaking into, 124-125
infiltrating, 122-124
linking with, 30-31
machine language exchanging
data, 104-108
memory layout, 92-102
variables, 102-105
BCC, Branch on carry clear, 87,
149
BCS, Branch on carry set, 149
BEQ, Branch on result zero, 149
Binary, defined, 2
Bit, defined, 2
BIT, Test bits in memory with
accumulator, 142, 149
Bit map mode on the 6566/6567,
328-330
BMI, Branch on result minus, 149
BNE, Branch on result not zero,
149
BOS, Bottom of string, 94-95
BPL, Branch on result plus, 149
Branches and branching, 79-80
Branch instructions, 141
BRK, Force-break, 72, 115, 116,
142, 143, 149, 279
Bus:
address, 4-5
control, 5
defined, 3
see also Data bus
BVC, Branch on overflow clear, 150
371
372 MACHINE LANGUAGE FOR COMMODORE MACHINES
BVS, Branch on overflow set, 1 50
Bytes, multiple, 58
C flag, 42, 45, 46
Character display mode of the
6566/6567, 325-327
Character sets, 242-250
Chip information, 293-356
6520 (PIA) Peripheral interface
adaptor, 294-298
6522 (VIA) Versatile interface
adaptor, 309-318
6525 Tri-port interface, 352-356
6526 (CIA) Complex interface
adaptor, 318-325
6545-1 (CRTC) CRT controller,
299-304
6560 (VIC) video interface chip,
304-309
6566/6567 (VIC II) chip
specifications, 325-340
6581 (SID) Sound interface
device, chip specifications,
340-351
CHKIN subroutine, 136
CHKOUT subroutine, 133, 134
CHRGET subroutine, 122-123,
124
CHRGOT subroutine, 123,
124-125
CHROUT subroutine, 25, 133
CIA chip, 120
CLC, Clear carry flag, 150
CLD, Clear decimal mode, 150
CLI, clear interrupt disable bit, 118
Clock speed, 132
CLOSE, 134
CLRCHN subroutine, 133, 135,
136, 137
CLV, Clear overflow flag, 150
CMP, Compare memory and
accumulator, 150
Color codes of the 6566/6567, 340
Commodore computers,
characteristics of, 156-166
Compare, 141
Comparing numbers, 61-62
Complex interface adaptor 6526,
318-325
Control bus, 5
CPX, Compare memory and index
X, 150
CPY, Compare memory and index
Y, 150
Data bus, 4-5
see also Bus
Data exchange, BASIC machine
language, 104-108
Debugging, 143
DEC, Decrement memory by one,
150
Decimal notation to hexadecimal,
7-8
DEX, Decrement index X by one,
150
DEY, Decrement index Y by one,
150
Disassembler, checking the,
29-30
Disk user's guide, 357-364
Division by two, 63-64
Do nothing insruction, 72-74
Dynamic string, 94
Effective address, 32
End of BASIC, 92-93
Envelope rates of the 6581 , 347
EOA, end of arrays, 93
EOR, exclusive or, 47, 48, 49, 121,
150
EOR instruction, 87
Exercises, 11-13, 52-54,
84-88, 252-278
INDEX
373
adding a command, 125-126,
256, 271-273
addition, 263-264
for Commodore CI 28, 257-276
file transfer, 274-276
input, 263
interrupt, 119-120, 254-255,
270-271
loops, 262-263
output, 273-274
print, 26-27, 259-262
screen manipulation, 265-266
Extended color mode of the 6566/
6567, 328
File transfer program, 138-141
Flags, 40-46
Floating point variables, 103
Free memory, 94-95
GETIN, Gets an ASCII character,
25, 133
Glossary, 365-369
Handshaking, 318-319
Hexadecimal notation, 5-6
Hexadecimal notation to decimal,
6-7
lA, Interface adaptor chips, 9, 50,
120-122, 142
lER, Interrupt enable register, 122
IFR, Interrupt flag register, 121
Immediate addressing, 148
Immediate mode, 74-75
Implied addressing, 148
Implied mode, 72-74
INC, Increment memory by one, 74,
150
Increment and decrement
instructions, 141
Indexed absolute addressing, 148
Indexed indirect addressing, 149
Indexed indirect mode, 83-84
Indexed zero page addressing, 148
Indexing modes:
absolute, 77-78
indirect, 81-82
zero page, 78
Index registers, 33
Indirect indexed addressing, 149
Indirect indexed mode, 81-82
Infiltrating BASIC, 122-124
Input, 50-52, 133
Input:
GETIN, 50-51
switching, 136-137
INSj increment, 72
Instruction execution, 10-11
Instruction set, 141-142, 147
alphabetic sequence, 149-151
Integer variables, 104
Interface adaptor chips, 9, 50,
120-122, 142
Interrupt enable register, 122
Interrupt flag register, 121
Interrupt processing, 40
Interrupt request, 115
INX, Increment index X by one, 150
INY, Increment index Y by one, 150
IRQ, Interrupt request, 115,
117-118
JMP, Jurhp to new location,
80-81, 141-142, 150
JSR, Jump to new location saving
return address, 114-115, 150
Jumps in indirect mode, 80-81
Jump subroutine, 142
Kernal, 24
Kernal subroutines:
CHKIN, 136
CHROUT, 25, 133, 134
374 MACHINE LANGUAGE FOR COMMODORE MACHINES
CLRCHN, 136
GETIN, 51
STOP, 52
LDA, Load accumulator with
memory, 150
LDX, Load index X with memory,
150
LDY, Load index Y with memory,
150
Light pen, 335
LOAD, 100-101
Logical and arithmetic routines, 141
Logical operators, 47-50
Loops, 32-34, 262-263
LSR, Shift one bit right (memory or
accumulator), 63-64, 150
Machine language and BASIC
exchanging data, 104-108
Machine language linking with
BASIC, 30-31
Machine language monitor SAVE,
99-100
Memory, free, 94-95
Memory contents:
changing, 17
displaying, 17
Memory elements, 8-9
Memory interface of the 6566/6567,
337-340
Memory layout, BASIC, 92-102
Memory maps:
B series, 203-212
CBM 8032, 179-180
Commodore PLUS/4 "TED" chip,
201-203
Commmodore 64, 191-200
Commodore 128, 213-230
FAT-40 6545 CRT, controller,
179-180
"Original ROM" PET, 168-172
Upgrade and BASIC 4.0 systems,
172-179
VIC 20, 181-187
VIC 6522 usage, 189-190
VIC 6560 chip, 188
Microprocessor chips, 650X, 3-4
MLM, Machine language monitors,
14, 284
MLM commands, 16-17, 99-100
.G command, 1 7
.M command, 16
.R command, 16
Save command, 99-100
.X command, 16
Modes:
absolute indexed, 77-78
addressing, 72-89
ail of zero page, 78
indexed, indirect, 83-84
indirect, indexed, 81-82
jumps in indirect, 80-81
no address, 72-74
no address accumulator, 74
not quite an address, 74-75
relative address, 79-80
single address, 75-76
zero page, 76-78
Monitors:
basic, 14
display, 15
extensions, 27-29
machine language (MLM),
14-15, 290-291
machine language SAVE,
99-100
Multi-color character mode of the
6566/6567, 327
Multiplication, 62-63
by two, 61-62
N flag, 42-43, 45, 46
Non-maskable interrupt (NMI), 115,
118
INDEX
375
NOP, No operation, 72-74, 85,
150
NOP BRK, No operation, breal<,
false interrupt, 142
Numbers:
comparing, 61-62
signed, 43-44, 58
unsigned, 58
Numeric variables, 104
OPEN, 133-134
ORA, "OR" memory with
accumulator, 47, 48, 49, 121,
150
Output, 133
controlling, 24-36
examples of, 135-136
switching, 133-135
Overflow, 44
PC, Program control register, 9
PEEK, 5, 104
PHA, Push accumulator on stack,
113, 150
PHP, Push processor status on
stack, 114, 150
PIA, Peripheral interface adaptor
6520, 120, 294-298
PLA, Pull accumulator from stack,
113, 114, 150
PLP, Pull processor status from
stack, 114, 150
Pointers, fixing, 102
POKE, 5, 26, 104
Program:
entering a, 18-19
running a, 30
Program Counter, 9-11, 149
Programming model, 151
Programming projects, 11-13,
52-54, 84-88, 252-278
adding a command, 125-126,
256
interrupt, 119-120, 254-255
print, 26-27
Programs, file transfer, 138-141
Pull information, 142
Push information, 142
Push processor status, 114
RAM, Random access memory, 8
Register map of the 6566/6567,
338-339
Registers, 9-10, 18
A, X, and Y, 9, 1 1 , 46, 47
index, 33
status, 45-46
Relative addressing, 148-149
mode, 79-80
ROL, Rotate one bit left (memory or
accumulator), 62, 150
ROM, Read only memory, 8-9
link, 80-81
ROR, Rotate one bit right (memory
or accumulator), 63-64, 150
Rotate, comments, 64-65
RTI, Return from interrupt, 115, 150
RTS, Return from subroutine, 65,
114-115, 151
RUN STOP key, 51-52
6502 Instruction set, 147
6509 Instruction set, 147
6510 Instruction set, 147
6520 (PIA) Peripheral interface
adaptor, 294-298
6522 (VIA) Versatile interface
adaptor, 309-318
6525 Tri-port interface, 352-356
6526 (CIA) Complex interface
adaptor, 318-325
6545-1 (CRTC) CRT controller,
299-304
6560 (VIC) Video interface chip,
304-309
376
MACHINE LANGUAGE FOR COMMODORE MACHINES
6566/6567 (VIC II) chip
specifications, 325-340
6581 (SID) Sound interface device,
chip specifications, 340-351
7501 Insruction set, 147
SAVE, 34, 141
stopgap, 34-35
SBC, Subtract memory from
accumulator with borrow, 151
Screen codes, 242-250
Screen manipulations, 84-88
Screen memory address, 21
SEC, Set carry flag, 1 51
SEP, Set decimal mode, 151
SEI, Set interrupt disabler status,
118, 151
Shift, comments on, 64-65
Shift and rotate instructions,
61-63, 74, 141
Signed numbers, 43-44, 58
Single address mode, 75-76
SOA, Start of arrays, 93
SOB, Start of BASIC, 92
Sound interface device (SID) chip
specification 6581, 340-351
SOV, Start of variables, 93,
97-102
SP, Stack pointer register, 9
SR, Status register, 9
STA, Store accumulator in memory,
151
Stack, 112-115
Status register, 45-46
Stop, 25, 51-52
Stopgap save command, 34-35
Storage, temporary, 112-115
String variables, 103
STX, Store index X in memory, 151
STY, Store index Y in memory, 151
Subroutines:
CHROUT, 25
GETIN, 25, 50-51
KERNAL, 24
prewritten, 24-25
STOP, 25, 51-52
Subtraction, 60-61
Supermen program, 27, 284-289
Supermon+ program, 290-291
Symbolic assemblers, 143-144
SYS, Go to the address supplied,
116
TAX, Transfer accumulator to index
X, 113, 151
TAY, Transfer accumulator to index
Y, 72, 113, 151
Testable flags, 40-45
Time of day clock, 321
Timing, machine language program,
132-133
TOM, Top of memory, 93-94
Tri-port interface 6525, 352-356
TSX, Transfer stack pointer to
index X, 151
Two's complement, 43
TXA, Transfer index X to
accumulator, 151
TXS, Transfer index X to stack
register, 151
TYA, Transfer index Y to
accumulator, 151
Uncrashing techniques, 280-281
Unsigned numbers, 58
USR, Go to a fixed address and
execute machine code there as
a subroutine, 116-117
Variables, 102-105
V flag, 44, 45, 46
VIA, Versatile interface adaptor,
120-121
VIC II chip specifications 6566/
6567, 325-340
INDEX
377
(VIC) Video interface chip 6560, Zero page addressing, 148
304-309 Zero page mode, 76-78
indexed, 78
Wedge, 122-124 Z flag, 40-41, 45, 46
program, 124-125
Pull up a chair and sit down with Jim Butterfield — the Commodore guru
himself — and get the answers to all your questions about machine lan-
guage with . . .
Machine Language for the
Commodore 64, 128, and Other
Commodore Computers
Revised & Expanded Edition /by Jim Butterfield
Authored by the world- renowned expert on all facets of the Commodore,
this comprehensive tutorial introduces programmers of all levels to the
principles of machine language — what it is, how it works, and how to
program with it. With speed and versatility, you'll share in Butterfield's
vast experience as you:
• Learn-by-doing — with easy-to-follow, step-by-step instructions, exam-
ples, and exercises
• Uncover the critical elements to understanding machine language,
machine architecture, and machine language tools
• Master principles of good coding practices — for more efficient and
effective programming
• Explore the inner workings of the Commodore, write and enter a simple
program, learn the details behind output, flags, logic, input, subrou-
tines, address modes, and more!
Not only an excellent tutorial, it's an invaluable resource you'll refer to
again and again!
TABLE OF CONTENTS
First Concepts / Controlling Output / Flags, Logic, and Input / Numbers,
Arithmetic, and Subroutines / Address Modes / Linking BASIC and
Machine Language / Stack, USE, Interrupt, and Wedge / Timing, Input/
Output, and Conclusion / Appendix A: The 6502/6510/6509/7501 Instruc-
tion Set / Appendix B: Some Characteristics of Commodore Machines /
Appendix C: Memory Maps / Appendix D: Character Sets / Appendix E:
Exercises for Alternative Commodore Machines / Appendix F: Floating
Point Formats / Appendix G: Uncrashing / Appendix H: A Do-It- Yourself
Supermen / Appendix I: lA Chip Information / Appendix J: Disk User's
Guide / Index
I 'l21898"66417' 4
Cover illustration by David Joly
Cover Design by Ben Santora
A Brady Book • Published by Prentice Hall Press • New York
ISBN 0-fl=13D3-bb4-l